The Computer Telephony Integration (CTI) component of CRM captures all calls, inbound and outbound. The CTI component also records the call length, missed calls, voice mails, personal calls, and caller IDs for demographic reporting information.
Traditionally, a CTI client such as incoming call monitor is implemented as a desktop Windows client. Now, with the increasing demand of Web interfaces among CRM products, it is no surprise that CTI is following suit.
Here is the task.
- The client side uses Microsoft Internet Explorer (IE) 4 with the cookie enabled for keeping session data.
- Only HTTP or HTTPS can be used as a communication protocol between IE and the servlet.
- The incoming call monitor pops up to ask for the CSR after he or she logs on.
- The incoming call monitor polls the CTI server periodically and asynchronously -- say, every five seconds -- without refreshing the page, while checking for any incoming calls for the CSR.
- Once an incoming call is pending, the incoming call monitor displays the phone number as well as the contact name if there is a match found in the CRM database for the phone number (shown in Figure 1).
Figure 1. Contact found
Obviously, the main hurdle is to poll the CTI server periodically and asynchronously for the incoming call without refreshing the page.
Remote scripting technique can solve this problem.You have two options to consider for remote scripting:
- The XML-RPC option is a remote procedure using HTTP as the transport and XML as the encoding. XML-RPC is designed to allow complex data structures to be transmitted, processed, and returned to the browser for display. JavaScript technology has an XML-RPC client side library and Java technology has a server side library. You need to install and configure these libraries to make XML-RPC work.
- The hidden IFRAME option has been part of the HTML specification ever since version 4, and is supported in nearly all modern browsers. With IFRAMER, you don't need to install client or server libraries.
XML-RPC requires the installation of XML-RPC libraries on both the server and client sides. XML-RPC is well suited for passing on larger amounts of data, while IFRAME is enough for small amounts of data.
Now I will analyze the amount of data that passed between client and server.
On the Java servlet side, polling for the incoming call can be done in a servlet method called getIncomingCall: String contactInfo=getIncomingCall(CSRUser csrUser).
Here is the detailed explanation of how this works.
- CSRUser is an object of Java class CSRUser. It is key in looking for the CSR's pending call in the incoming call queue (its class is CSRUser).
After the CSR logs on, you can create and store a CSRUser object in the HttpSession, and the servlet container will set a cookie and send it back to IE. Therefore, when IE polls the servlet, an HTTP session cookie is always passed from the IE to the servlet; the cookie can then be used to find the CSRUser object in the HttpSession object. It is familiar to any servlet developer.
As a result, no data is passed explicitly from IE to the servlet because the session cookie is passed on as a key to look up CSRUser anyway.
- getIncomingCall is the instance method of the servlet. You need instance method here because only an instance method can get access to HttpServletRequest, which eventually will acccess the CSRUser. The logic behind getting the CSRUser from HttpServletRequest and HttpSession is that it can be done only by the servlet's base class.
- contactInfo is the data returned by the getIncomingCall. It gives a string of contact IDs, contact names, or phone numbers in the form of either a name value pair, or a nocall, which means no incoming calls are in queue yet for this CSR. The contact ID is the unique identifier for this customer and is useful for the subsequently generated Web pages.
Given that no data is passing explicitly from the client side to the server side, and only a String of limited length is to be passed from the server side back to the client side, IFRAME is lean and mean enough to work as the incoming call monitor. All you have to do is make an HTTP GET or POST from IE to the servlet inside a hidden IFRAME; then the servlet generates HTML (actually, JSP or JavaServer Page file) back to the hidden IFRAME. To pass the returned data, such as contactInfo, inside the JSP file, you can invoke a JavaScript function with the contactInfo as parameter. Once IE loads this JSP file, this callback function is called.
Erik's article (see Resources) builds a framework to support a hidden IFRAME. However, the framework is lacking the support it needs to invoke an instance method of the servlet (static method only in his framework), which carries HttpServletRequest or any user-defined datatype, such as CSRUser, as the input parameter. Most J2EE Web applications access the business object (csrUser, in this case) through the HttpSession because it serves as the single entry point to the object model.
In order to do that, I need to enhance Erik's RemoteScriptingServlet base class. Furthermore, the framework can be simplified to improve efficiency, given that polling from each CSR's incoming call monitor can put a heavier load on the server side. Again, I can do this because I don't need to send large amounts of data back and forth.
Enough talk; here comes the code
The code snippets are arranged in the same order in which they execute.
Figure 2 shows the Incoming Call Monitor as created with the monitor.jsp file.
Figure 2. Incoming call monitor (monitor.jsp)
A few lines of JavaScript and HTML can get the job done in monitor.jsp and rpc.jsp.
Define a zero height- and width-hidden IFRAME called "ctiframe" (making it invisible on the Web page).
Listing 1. Define a hidden IFRAME (monitor.jsp)
<iframe id="ctiframe" width=0 height=0 border=0 > </iframe> |
init() polls the server every five seconds inside checkCall() after the page loads.
checkCall() makes an HTTP GET request inside the hidden IFRAME to AnyCallServlet's (mapped from /anycall according to WEB-INF/web.xml) getIncomingCall method (instance method).
Listing 2. Create an HTTP GET request in the hidden IFRAME (monitor.jsp)
function init() {
setInterval(checkCall, 5000);
}
// RPC function on server side
function checkCall() {
document.all.ctiframe.src='/cti/anycall?rsfunc=
getIncomingCall&callback=gotCall';
}
|
All I have to do now is implement the remote method: String getIncomingCall(CSRUser user) in the AnyCallServlet class.
This remote method is called by the superclass RSServlet's doGet(). RSServlet is the major workhorse for invoking the remote method using the Java Reflection API. The idea comes from Erik's work, except the remote method is an instance method here rather than a static one. This gives the advantage gaining access to the object model in the CRM system.
Consider the sky your limit when it comes to scripting remotely. As long as that remote method takes CSRUser as an argument, you can make any remote method call on any subclass of RSServlet. Go ahead and apply this to any of the ideas in your imagination.
Listing 3. Make remote method calls on RSServlet subclasses
public class AnyCallServlet extends RSServlet {
static final String NO_CALL="nocall";
// helper method get the User
public CSRUser getUser(HttpServletRequest request) {
// get the HttpSession from the request
HttpSession session=request.getSession(false);
// get the CSRUser from HttpSession
CSRUser user=(CSRUser)session.getAttribute("user");
return user;
}
public String getIncomingCall(CSRUser user)
{
IncomingCall call = CallQueueManager.getPendingCall(user);
String retVal=NO_CALL;
if (call!=null) retVal=call.toString();
return retVal;
}
|
The IncomingCall class has a toString() method that returns contactInfo in an ampersand-separated name value pair that eventually gets sent to IE.
Listing 4. toString() method returns contactInfo
public class IncomingCall {
public String toString() {
return "contactid="+contact.getId()+"&name="+callerName+
"&no="+callerNumber;
}
}
|
The servlet forwards to a JSP file (rpc.jsp) for this hidden IFRAME. The JSP file calls window.parent.gotCall() (window.parent refers to the windows that monitor.jsp lives in) with the returned value as a String from the remote method getIncomingCall. Note that the values for callback and rpcvalue will be set in RSServlet.doGet().
Listing 5. Servlet requests results from the hidden IFRAME (rpc.jsp)
<script>
window.parent.<%=request.getParameter("callback")%>
('<%=request.getAttribute("rpcvalue")%>')
</script>
|
gotCall() is the callback function which is invoked by IFRAME's rpc.jsp as above with the contactInfo as parameter. Then it invokes contact.jsp to display the contact name and phone number to the CSR.
Listing 6. IFRAME's rpc.jsp invokes the callback function (monitor.jsp )
// call back function
function gotCall(retVal) {
if (retVal.indexOf('nocall')!= 0) {
document.location.href="/cti/jsp/contact.jsp?"+retVal;
}
}
|
The code is tested on Tomcat 4.1.27 and can be simply unzipped to Tomcat's webapps directory where you'll find the README file. After Tomcat starts up successfully, go to http://localhost:8080/cti/ to see the demo. The code is distilled to illustrate key design and implementation techniques, though not for a full blown version.
| Name | Size | Download method |
|---|---|---|
| wa-remotescrpt-cti.zip | HTTP |
Information about download methods
- Read Erik Hatcher's article, ""Remote scripting using a servlet"" which is the base and architectural foundation for this article (developerWorks, February 2001).
- Review the specifications on XML-RPC.com.
- Visit the XML-RPC implementation in JavaScript (vcXMLPRC).
- Read this helpful article on "Exchanging information with a server without reloading your HTML page" (developerWorks, January 2002).
- Check out this explanation of JSRP, or Java Script Remote Scripting, on the SourceForge site.
- Download the source code used in this article.
Victor Yongwei Yang is working for IBM's Toronto Lab as a software developer. He holds a MSCS from Georgia Tech. Since 1994 he has worked for numerous companies including AT&T, S1,IBM, Sun Microsystems, SunLife, and CIBC. He is a Sun certified programmer and Web developer. He can be reached at victory@ibm.ca.com or yanixsoft@yahoo.com.



