All
other trademarks are the property of their respective owners. No part of this document may be reproduced, stored in or introduced
into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise),
or for any purpose, without the express written permission of RightNow Technologies.
RightNow
Integration and Customization
for Developers
Student Guide
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Table of Contents
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 1
There are many resources available to assist you while you are working with this
course and related material. Registration may be required to view some of these
resources. These resources include:
RightNow Developer Community:
http://community.rightnow.com/developers.php
o This area contains full developer documentation and code samples,
discussion forums, a developer blog, and conference presentations.
RightNow CX Users Guide:
o Downloadable PDF from http://www.rightnow.com under
Community > Customers > Documentation
Other training and tutorials: http://www.rightnow.com/services-
training.php
RightNow Developer Conference: http://www.rightnow.com
RightNow CX, which stands for Customer Experience, is a suite of applications that
empowers enterprises to engage directly with their customers through Social, Web,
and Contact Center experiences. 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 has its own unique URL.
RightNow CX empowers customers to get help from a self-service web site and/or
support from live agents who use an application called the Agent Desktop to handle
customer issues. Although the full suite of 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 which it depends.
Customer service agents and administrators can access a RightNow site via the Agent
Desktop. That requires downloading and installing the RightNow CX Agent Desktop,
which provisions a local machine with the needed components to accessing a
particular site.
Customers of an enterprise that uses RightNow can use a CustomerPortal web site to
interact with the RightNow knowledge base 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 RightNow APIs, one
of which allows customization of the Agent Desktop.
This course begins with a look at the Agent Desktop to familiarize you with the most
common entities in RightNow CX.
You have been assigned your own RightNow knowledge base, 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.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 4
Site URL (end-user): http://___________________.rnowtraining.com
Site URL (admin/launch):
http://___________________.rnowtraining.com
/cgi-bin/__________________.cfg/php/admin
/launch.php
URL for site WSDL
http://_________.rnowtraining.com/cgi-
bin/_________.cfg/services/soap?wsdl
Admin Username: cxadmin
Admin Password: cxadmin
To install the client application that accesses a 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 RightNow CX. Click this button and wait for the
brief installation.
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.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 5
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 log in to your site.
1 Type the URL for your site into the address bar of Internet Explorer.
<sitename>.rnowtraining.com/cgi-
bin/<sitename>.cfg/php/admin/launch.php
2 Click the Install RightNow CX button. This begins a download to
your workstation, which may take several minutes.
3 In the Login window, type your username and password.
4 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.
The RightNow console 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 RightNow database. 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 particular record type
is known as the Workspace for that record type.
A contact center agent uses the RightNow 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.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 6
In this activity, you will access and view a list of Contacts and open a single Contact
for editing.
1 From the Navigation pane, click Contacts.
2 Double-click Contact Search.
3 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.
4 The list of Contacts is displayed.
5 To see details of an individual Contact, double-click to open the record.
In this activity, you will create a new answer that explains how to reset a password.
1 Go to Answers > Answers Default > Search.
2 Click New and type Summary: Password Reset
3 Set Answer options.
Status Public
Language English
Access Level Everyone
Answer Type HTML
4 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.
5 Click the Products/Categories tab and select General and Technical
Support.
6 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 9
Like many enterprises, Smartech wants to customize 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
indicident 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 RightNow to add a new incident status value to a
menu.
1 Go to Configuration > Application Appearance >
Customizable Menus.
2 Expand System Menus and select Incident Statuses.
3 Click New and type the Label: Researching.
4 Assign Status: Unresolved to have this status marked as open.
5 Click Save & Close.
6 Select the Incidents tab, then click on the New icon to open a new
incident record.
7 Select Status to see the new value within the list.
In this activity, you will create a custom field on the Incidents table.
1 Select Configuration > Database > Custom Fields > Incident.
2 Click New to create a new Incident custom field.
3 Type Name: Urgent?.
4 Select Data Type: Yes/No.
5 Type the Column Name: urgent.
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.
6 Click Save & Close, then click Yes.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 10
In this activity, you will configure a custom workspace to display the custom field.
1 Select Configuration > Application Appearance >
Workspaces/Workflows > Standard.
2 Right-click Incident and select Copy.
3 Type Name: Custom Agent Workspace, then click OK.
4 Select the Workspaces and Workflows folder, and open Custom
Agent Workspace.
5 Click on the Insert Field tab.
6 Scroll down to the Urgent? field and drag and drop it onto the
workspace.
7 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 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 Smartechs RightNow database,
you will need to use a staff account that has a profile with the appropriate
permissions.
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 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 Go to Analytics > Reports Explorer.
2 Click Find from the ribbon, then select Find using: Name.
3 Select Match for the operator.
4 Type Agent into the text box and click Find.
5 Double-click Agent Activity found in the right pane of the Reports
Explorer to run the report.
6 You can select filters in the Search dialog. Make the Date Range start
value 01/01/2010.
7 Click Search and view the results.
A dashboard is a combination of individual reports shown from a single report
location. Dashboards can be customized with a choice of reports and layouts.
You would like to have a dashboard available for your own use. As a developer, the
reports you're interested in are under Site Administration. You want to include:
Custom Fields
o Common > Site Administration > Custom Fields
Products
o Common > Site Administration > Customizable Menus
Public API Meters
o Common > Site Administration > Public API
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 12
In this activity, you will create a Dashboard, including the following reports: Custom
Fields and Products.
1 Go to Analytics > Reports Explorer.
2 Click New Dashboard.
3 In the left panel, expand Common > Administration > Custom
Fields.
4 Drag and drop the Custom Fields report into the upper panel.
5 Expand Site Administration > Customizable Menus, and drag
and drop Products into the lower panel.
6 Click Save from the Quick Access area above the main ribbon. Save in
the My Reports folder and type Name: Developer Dashboard. Click
OK.
7 To run the dashboard, navigate to Reports Explorer > My Reports,
then double-click Developer Dashboard.
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 customers 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. The Object Designer is a
graphic 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 deploying it to your production environment.
Custom objects are stored in packages which also scope the objects.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 13
To use the Object Designer, Custom Objects must be enabled on your site, and the
user must have the Object Designer permission enabled in his or her profile. This can
be done by a site administrator.
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 Select Configuration > Database > Object Designer.
2 Click New and select Package.
3 Name the package Classes.
4 Select the Classes package and click New > Object.
5 Type Name: TrainingClass.
6 Click Fields in the ribbon, then select Add New Field.
7 Select Integer.
8 Type field Name: ClassNumber, avoiding spaces.
9 Click the Add New Field button again.
10 Select Text.
11 Type field Name: ClassName, avoiding spaces.
12 Type Length of Field: 50.
13 Click Save, then Deploy.
14 Type in your email address, then check Deploy Immediately. In a
real scenario, you could schedule deployment for a time when the
potential performance hit would be least problematic.
15 Click Deploy, then confirm Yes.
16 Wait until the deployment finishes.
17 Select Configuration > Application Appearance >
Workspaces/Workflows > Standard.
18 On the ribbon, click New Workspace.
19 Select TrainingClass Multi-Edit.
20 From the Fields group on the ribbon, drag each of the two fields onto
the blank area of the new workspace.
21 Click on the Preview button to see how the new workspace will look to
the agent user.
22 Click the Save & Close icon above the ribbon.
23 Name the new workspace Training Class.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 14
The RightNow Application 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.
RightNow 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 is integrated with RightNow Service so customers can 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 RightNow database are being used through
the Right Now CX suite, 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 RightNow.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 15
In this activity, you will explore and interact with the Customer Portal support pages
of your site.
1 Open the end-user pages of your training site in a browser:
http://<sitename>.rnowtraining.com.
2 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 your question (Incident), and
that it identifies you as the Contact.
What are some of the basic entity objects in RightNow CX and how are they used?
Give some examples of configurations that can be made to the Agent Desktop by a
CX Administrator, without requiring coding.
Why might an administrator need to create a new Staff Account? What profile bits
must be enabled for a developer account?
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 16
How do you run and view a basic Analytics report in the Agent Desktop?
Why might you create a Custom Object?
What tool is used to design and create a Custom Object?
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 17
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 Framework to automate, extend, or integrate the Agent
Desktop.
Code that uses CCOM objects indirectly accesses data from 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 sub-
objects.
Sub-objects, in general, cannot be directly manipulated with CRUD operations but
instead are manipulated through operations on the primary object in which they are
embedded. Sub-objects can contain sub-objects of their own.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 20
For Read operations, the Connect APIs use a special 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 23
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.
The API call is executed 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 24
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 25
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);
}
Using Web Services for SOAP requires having II_CONNECT_ENABLED set for
the relevant site. In addition, the user credential supplied with the client must be for
an account in which the Public SOAP profile permission has been set.
To create a simple executable that can retrieve data with ROQL and Web Services for
SOAP, use a Console Application project type. To access the WSDL, add a Service
Reference to the relevant RightNow site:
http://sitename.rnowtraining.com/cgi-bin/
sitename.cfg/services/soap?wsdl
Then add using statements for the namespaces for the Service Reference and for the
namespace System.ServiceModel.
using ConsoleApplication1.ServiceReference1;
using System.ServiceModel;
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 for integration.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 26
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, an object template
which defines what level of data will be returned for each object, and a row
maximum.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 27
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 28
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 29
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 30
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, 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 31
Aggregate functions are available in tabular (CSV) queries only.
Prior to November, 2011, 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.
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 32
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
FROM Contact
WHERE CustomFields.c.age IS NOT NULL
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
All the text in all the threads for incidents where the organization is
"Intertrade Malls"
ROQL does not support regular SQL-type joins, but it provides 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 <Parent Object>.<Parent to Child
Relationship Name>.<Property of Child Object> FROM <Parent
Object>
SELECT <Child Object>.<Child to Parent Relationship Name> FROM
<Child Object>
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 34
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 non-
matches.
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 C.PrimaryContactIncidents.CreatedTime
FROM Contact C
WHERE C.ID = 99 AND C.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 alias 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.
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 36
You need to return and display results in groups of 3, instead of all at once.
In this activity, you will use multiple queries to re-write a query in existing code in
MultipleQueries_Starter.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 39
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]);
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 40
Connect Web Services for SOAP 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 running 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 object 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 43
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.
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 will 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 50
Before this code is executed, you must have the ID of the object to be updated, in
this case an Organization. You might obtain the ID through a ROQL query or a Get
operation. That ID will be set into a new instance of the Organization type, as in line
four of the code snippet below (in place of <id>), 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 = <id of object to be updated>;
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 an Update operation has no useful data, not even a 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 51
In this activity, you will write an app to change the email for the new contact you
created earlier to another email of your 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 53
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 same 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 once. 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) are:
Create an instance of the primary object 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 the
entire Incident will not be deleted.
For more information on how and when related objects or fields are changed on a
delete of another object, see the RightNow documentation.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 54
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 62
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.
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
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 66
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, which
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 application to instantiate and populate an instance
of TrainingClass, and then to retrieve and display the data from the object just
created.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 67
Connect Web Services for SOAP also includes operations to handle operations that
are not basic CRUD functions:
Running an Analytics Report
Getting values for a NamedID type
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);
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 68
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 70
In this activity, you will write code to get the IDs and names required.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 71
What are the three arguments to CRUD operations methods?
What are the advantages/disadvantages of providing the name instead of the ID of a
NamedID type?
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?
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 72
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 all users, and to test it
after uploading it.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 73
In this activity, you will upload an existing compiled Add-In DLL to the RightNow
server for your site.
1 From the Agent Desktop, go to Configuration > Site Configuration >
Add-In Manager.
2 Click New and browse for MyAddIn.dll (located in the
"\Starter\Uploading an Add-In\ClassLibrary1\bin\Release" folder)
and click Open.
3 Click the Profile Access button on the ribbon and select CX All 2 for
profile, and All for the interfaces.
4 Click Save & Close.
5 Close and re-open the Agent Desktop.
6 Locate the button in the Home navigation set and click to test that it
changes the color of its section.
The RightNow Connect Desktop Add-In Framework makes it easier for developers to
write add-ins such as custom controls or components.
An Add-In is compiled into a Dynamic Link Library (DLL).
The RightNow Connect Desktop Add-In Framework leverages the .NET Add-In
Framework, which is in the System.AddIn namespace.
The Add-In Framework is designed to create code that will be backwardly compatible
in future releases of CX.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 74
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 Add-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 Add-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 appropriately 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 and
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 75
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 three classes:
RibbonTab
RibbonGroup
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 76
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 clickable menu item buttons.
Optionally, you can place an image on the 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.
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 77
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 add-in needed in the scenario.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 78
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\righNumberLetterCombo\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 2012, Oracle and / or its affiliates. All rights reserved.
Page 79
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 the 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 add-
ins 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 80
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.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 81
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.
In this activity, you will implement the requirements of the scenario above, first by
writing the Add-In and compiling the code so that the Add-In will be activated in the
workspace in Developer mode. Then close and re-open the Agent Desktop to load
the Add-In. 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 Open Configuration > Application Appearance >
Workspaces/Workflows.
2 Click New Workspace.
3 In the dialog, click Task under Standard Types.
4 Click the arrow to expand the Fields group, select Task ID, and drag
it onto the top section of the new workspace.
5 From the Workspace Properties group, click on Ribbon.
6 In the dialog, click Edit Tab to edit the Home tab.
7 In the Editing Tab, Actions group, click Edit Group.
8 All existing buttons on the ribbon in the Actions group are shown.
Click Add Button.
9 Check the box to add the custom button, Check Task Update
Status, from the list. Click OK.
10 Preview the customized ribbon. Click OK.
11 On the Quick Access toolbar, click Save & Close. Type Name: My
Task Workspace, and place it in the \Workspaces and Workflows
folder. Click OK.
12 Assign this new workspace to your profile. Go to Configuration >
Staff Management > Profiles.
13 Double-click to open the CX All profile. Under the
Workspaces/Workflows tab, scroll down to Task. Click the
search icon at the far right of the Task row.
14 In the dialog, select My Task Workspace and click OK.
15 Click Save & Close.
16 Now test your button. From the Navigation Pane, select Tasks.
17 Double-click Recently Modified Tasks.
18 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 2012, Oracle and / or its affiliates. All rights reserved.
Page 85
Navigation Items are similar to the Navigation Section from the first exercise in that
they can be used to customize a Navigation Set. However, 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.
Calls to the Web Service for SOAP API 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://<sitename>/cgi-bin/<sitename>.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<SecurityBindingElement>().
IncludeTimestamp=false;
_client.Endpoint.Binding = new CustomBinding(elements);
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 86
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.
The documentation for the Desktop AddIn 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.
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.
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 87
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 88
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 2012, Oracle and / or its affiliates. All rights reserved.
Page 89
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.
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
Continued on next page
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 90
To see what Add-Ins are currently active and inactive, click the Application Button in
the upper left and select RightNow CX Options > Add-Ins.
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 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.
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 browser to http://www.merriam-
webster.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.
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 92
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using ConsoleApplication1.ServiceReference1;
6 using System.ServiceModel;
7 using System.IO;
8
9 namespace ConsoleApplication1
10 {
11 class Program
12 {
13 private static RightNowSyncPortClient _client;
14
15 static void Main(string[] args)
16 {
17 Program program = new Program();
18 program.QueryContact();
19 }
20
21 public Program()
22 {
23 _client = new RightNowSyncPortClient();
24 _client.ClientCredentials.UserName.UserName = "xxx";
25 _client.ClientCredentials.UserName.Password = "yyy";
26
27 }
28 void QueryContact()
29 {
30 ClientInfoHeader clientInfoHeader = new ClientInfoHeader();
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 93
31 clientInfoHeader.AppID = "Identifier goes here";
32
33 try
34 {
35 byte [] output = null;
36 CSVTableSet tableSet = _client.QueryCSV(clientInfoHeader,
37 "SELECT Contact.Name.Last, Contact.ID FROM Contact WHERE Contact.ID < 7",
38 10000, ",", false, false, out output););
39 CSVTable[] tables = tableSet.CSVTables;
40
41 foreach (CSVTable t in tables)
42 {
43 System.Console.WriteLine("Name: " + t.Name);
44 System.Console.WriteLine("Columns: " + t.Columns);
45 String[] rows = t.Rows;
46
47 foreach (String data in rows)
48 {
49 System.Console.WriteLine("Row Data: " + data + Environment.NewLine);
50 }
51 }
52 }
53 catch (Exception ex)
54 {
55 Console.WriteLine(ex.Message);
56 }
57 PressAnyKey();
58
59 }
60
61 void PressAnyKey()
62 {
63 System.Console.WriteLine(Environment.NewLine + "Press any key to continue");
64 Console.ReadKey();
65 System.Console.WriteLine(Environment.NewLine);
66 }
67 }
68 }
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 94
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 95
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using ConsoleApplication1.ServiceReference1;
6 using System.ServiceModel;
7
8
9 namespace ConsoleApplication1
10 {
11 class Program
12 {
13 private static RightNowSyncPortClient _client;
14
15 static void Main(string[] args)
16 {
17 Program program = new Program();
18 program.QueryContact();
19 }
20
21 public Program()
22 {
23 _client = new RightNowSyncPortClient();
24 _client.ClientCredentials.UserName.UserName = "xxx";
25 _client.ClientCredentials.UserName.Password = "yyy";
26
27 }
28 void QueryContact()
29 {
30 ClientInfoHeader clientInfoHeader = new ClientInfoHeader();
31 clientInfoHeader.AppID = "Identifier goes here";
32 Contact contactTemplate = new Contact();
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 96
33 RNObject[] objectTemplates = new RNObject[] { contactTemplate };
34
35
36 try
37 {
38 QueryResultData[] queryObjects = _client.QueryObjects(clientInfoHeader,
39 "SELECT Contact FROM Contact WHERE Contact.Address.City='Singapore'",
40 objectTemplates, 10000);
41 RNObject[] rnObjects = queryObjects[0].RNObjectsResult;
42
43 foreach (RNObject obj in rnObjects)
44 {
45 Contact cont = (Contact)obj;
46 Console.WriteLine(cont.Name.Last + ", " + cont.Name.First);
47 }
48 }
49 catch (Exception ex)
50 {
51 Console.WriteLine(ex.Message);
52 }
53 }
54 }
55 }
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 97
Copyright 2012, Oracle and / or its affiliates. All rights reserved.
Page 98