Overview  

  Code Examples  

 

  Previous Section   Next Section 

FRAMES     NO FRAMES    


 

Contents

 

Developing a CSTA application to monitor a device. 1

Creating the project and adding the Java files. 2

Create the project 2

Add two Java classes to the project 2

Adding the code. 2

Customizing the code for your environment 3

Update the address of the CSTA signaling manager to point to your OpenScape Voice  3

Update the phone number you will monitor 3

Running the CstaMonitor example. 4

Understanding the CstaMonitor example code. 7

The source code for the monitoring example. 10

Developing a CSTA application to control calls. 13

Creating the project and adding the Java files. 13

Create the project 13

Add three Java classes to the project 13

Adding the code. 14

Customizing the code for your environment 14

Update the address of the CSTA signaling manager to point to your OpenScape Voice  14

Update the phone number you will monitor 15

Update the phone number where you will deflect the call 15

Running the CstaCallRouter example. 16

Understanding the CstaCallRouter example code. 17

The source code for the CSTA Call Router example. 21

 

Developing a CSTA application to monitor a device

 

In this section we will develop a simple CSTA application that monitors a device and prints the events as they arrive. The topics illustrated in this section:

  • Connecting to the CSTA server
  • Monitoring a specific device
  • Disconnecting from the server.

 

The full source code for the application is shown at the end of the section.

 

Creating the project and adding the Java files

In this section we will create project we will use in the first example. When we finish the session the source files will be empty. We will add the source code in the next section.

 

Create the project

  • Create a new project and set it up as explained in this section. Name that project CstaMonitor.

Add two Java classes to the project

  • Right-click the src and choose New à Class.
  • Enter CstaMonitorMain in the name field.
  • Click on Finish (this will create the class in the default package - not advisable for large project, but simple enough for our sample code).
  • Repeat the steps to create the CstaDeviceMonitor class.

 

At this point the project will look like this in eclipse:

 

image001

 

Adding the code

We will now copy the source code into the new files. Don't worry about understanding the code for now. It will be explained later. First we will run it to see how the CSTA SDK behaves, and then we will go over the important pieces.

 

Add the code for CstaMonitorMain

  • Open the CstaMonitorMain.java file in the editor
  • Erase the existing text in CstaMonitor.java, if any (eclipse may have added text from the class template configured in the environment)
  • Copy the code from this section and paste it in the editor
  • Save the file

Add the code for CstaDeviceMonitor

 

Customizing the code for your environment

Before running the code it needs to be adapted for your environment: Open the file CstaMonitorMain and make these changes:

 

Update the address of the CSTA signaling manager to point to your OpenScape Voice

Change the constant CSTA_SERVER_IP_ADDRESS to the IP address of the CSTA signaling manager in your environment. If you don't the address, ask the administrator of that OpenScape Voice system.

Update the phone number you will monitor

The number in the code must match exactly the FQN (e.g. +15619231000) of the number what is configured in the OpenScape Voice. 

This must be a phone that has the CSTA service assigned to it in OpenScape Voice.

Note that there is also a constant for the CSTA signaling manager port number (CSTA_SERVER_PORT). There is rarely a need to change the port number. It's here for completeness only. The highlighted text below shows the places that need to be adapted to your environment:

 

public class CstaMonitorMain

{

   /**

    * The IP address of the CSTA interface in OpenScape Voice

    */

   private static final String CSTA_SERVER_IP_ADDRESS = "ip address goes here";

 

   /**

    * The port number - it's usually 1040, very rarely changed

    */

   private static final int    CSTA_SERVER_PORT       = 1040;

 

   /**

    * The phone number we will monitor Must match the configured in OSV and must

    * have CSTA service assigned

    */

   private static final String DEVICE_TO_MONITOR      = "phone number goes here";

}

Running the CstaMonitor example

Now the code is in place and adapted to your environment.

Before running the code, make sure that the OpenScape Voice is configure to run CSTA applications and that the number you selected for the example has the CSTA service assigned. See details in this section.

This example is a command line Java application. We will follow it in the Console window of eclipse. If that window is not visible, select Window à Show View à Console to make it visible.

Use the Run à Run menu option or click on the run button in the toolbar.

The first few lines in the console are from the CSTA SDK, logged with log4j. They will look like this:

2010-08-24 07:18:39,189 [main] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - Connected to CSTA Server.
2010-08-24 07:18:39,423 [main] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 07:18:39,423 [main] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 0009<?xml version="1.0" encoding="UTF-8"?><SystemStatus...
2010-08-24 07:18:39,533 [main] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Sent CSTA Message: 0009<?xml version="1.0" encoding="UTF-8"?><SystemStatusResponse ...

...and a few more lines like that.

Then the code in our example will run. It will log the connection and the monitor start operations, shown in blue text.

                             

...a few more logs from the CSTA SDK            

---

Connected to 172.20.34.70

---

 

... more logs from the CSTA SDK

---

Started monitoring 15619231972

---

              

The last line in the screen is the prompt to terminate the example application:

Press Enter to exit

At this point if you leave the application running you will see a few logs from the CSTA SDK that look like these ones:

2010-08-24 07:19:39,970 [Timer-0] DEBUG com.sen.openscape.csta.transport.CstaLink - Sending RequestSystemStatus Request
2010-08-24 07:19:39,986 [Timer-0] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Sent CSTA Message: 0012<?xml version="1.0" encoding="UTF-8"?><RequestSystemStatus ...
2010-08-24 07:19:40,205 [Thread-1] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 07:19:40,205 [Thread-1] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 0012<?xml version="1.0" encoding="UTF-8"?><RequestSystemStatusResponse ...

This is the heartbeat between the application and OpenScape Voice. If the heartbeat fails, both the application and OpenScape Voice know that the connection is broken. They can recover the resources associated with the connection (sockets, allocated memory, etc.). Please note that SDK does not recover the connection automatically. SDK throws CstaException with Network failure and the Application has to handle the Exception and decide to restart the connection or not.

To get some events to analyze, make a call to the number you are monitoring, answer that call and release it.

In eclipse's console we will see the CSTA events for that call. The traces from the CSTA SDK show the full contents of the CSTA message as received from OpenScape Voice. That XML is parsed by the SDK and delivered as a Java event to the application, with the data from the XML message extracted as fields of the event. We will see that in more details when we analyze the code.

This is the very first message received from OpenScape Voice:

2010-08-24 08:29:34,402 [Thread-1] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 08:29:34,402 [Thread-1] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 9999<?xml version="1.0" encoding="UTF-8"?><DeliveredEvent . . .
2010-08-24 08:29:34,434 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection is valid.
2010-08-24 08:29:34,434 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection callID=FF000100000000002EBB734C18000000;deviceID=+15619231972 is added to the list

This log is from our example application, when it receives the event from the CSTA SDK:

--- Device 15619231972 received event: type=DELIVERED, service ID=15619231972
 
                              

This log comes from the piece of code below from our application. Note that at this point we no longer deal with the XML from OpenScape Voice. The CSTA SDK parsed the XML and filled in the event fields.

  @Override

  public void newCstaEvent(CstaEventObject evt)

  {

     System.out.print("\n--- Device " + evt.fqnDn + " received event: type=" + evt.evtType

           + ", service ID=" + evt.callID + "\n");

  }

 

These are the other events as the call is answered, then released:

2010-08-24 08:29:34,949 [Thread-1] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 08:29:34,949 [Thread-1] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 9999<?xml version="1.0" encoding="UTF-8"?><DeliveredEvent . . .
2010-08-24 08:29:34,965 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection is valid.
2010-08-24 08:29:34,965 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection callID=FF000100000000002EBB734C18000000;deviceID=+15619231972 is updated in the list
 
                --- Device 15619231972 received event: type=DELIVERED, service ID=15619231972
              
                               
2010-08-24 08:29:36,590 [Thread-1] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 08:29:36,590 [Thread-1] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 9999<?xml version="1.0" encoding="UTF-8"?><EstablishedEvent . . .
2010-08-24 08:29:36,605 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection is valid.
2010-08-24 08:29:36,605 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection callID=FF000100000000002EBB734C18000000;deviceID=+15619231972 is updated in the list
                              
                --- Device 15619231972 received event: type=ESTABLISHED, service ID=15619231972
                               
              
2010-08-24 08:29:39,730 [Thread-1] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 08:29:39,730 [Thread-1] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 9999<?xml version="1.0" encoding="UTF-8"?><ConnectionClearedEvent . . .
2010-08-24 08:29:39,746 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection is valid.
2010-08-24 08:29:39,746 [Thread-1] DEBUG com.sen.openscape.csta.callcontrol.CstaMonitor - Connection callID=FF000100000000002EBB734C18000000;deviceID=+15619231972 is removed from the list
                 
              
                --- Device 15619231972 received event: type=CONNECTIONCLEARED, service ID=15619231972
              
                               
2010-08-24 08:29:52,948 [Timer-0] DEBUG com.sen.openscape.csta.transport.CstaLink - Sending RequestSystemStatus Request
2010-08-24 08:29:52,948 [Timer-0] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Sent CSTA Message: 0015<?xml version="1.0" encoding="UTF-8"?><RequestSystemStatus . . .
2010-08-24 08:29:52,995 [Thread-1] DEBUG com.sen.openscape.csta.transport.tcp.CstaTcpLink - MessageLength=4
2010-08-24 08:29:52,995 [Thread-1] INFO  com.sen.openscape.csta.transport.tcp.CstaTcpLink - Received CSTA Message: 0015<?xml version="1.0" encoding="UTF-8"?><RequestSystemStatusResponse xmlns="http://www.ecma-international.org/standards/ecma-323/csta/ed4"><systemStatus>normal</systemStatus></RequestSystemStatusResponse>
 
                 
              

Understanding the CstaMonitor example code

The code has two main pieces:

  • Connect to OpenScape Voice
  • Request to monitor a device

The first part, connecting to OpenScape Voice, is done in the connect function in CstaMonitorMain.java. They key function call is highlighted in bellow.

                  

  public class CstaMonitorMain

  {

  ...

     private static CstaProvider connect()

     {

        CstaConfiguration cfg = new CstaConfiguration(CSTA_SERVER_IP_ADDRESS, CSTA_SERVER_PORT);

        try

        {

           CstaProvider provider = new CstaProvider();

           provider.connectToSystem(cfg);

           System.out.println("\n---\nConnected to " + CSTA_SERVER_IP_ADDRESS + "\n---\n");

 

           provider.startHeartbeat(60, 60);

           return provider;

        }

        catch (CstaException e)

        {

           System.err.println("Failed to connect: " + e.toString());

           return null;

        }

     }

After that point we have a CstaProvider object that we will use throughout the code.

CSTA-SDK will connect to OpenScape Voice Server using raw TCP connection by default. Since CSTA-SDK V1.2.0, HTTP/SOAP connection is supported on OpenScape Voice Server V7 or higher.

To connect using HTTP/SOAP connection, set the following in CstaConfiguration object:

       CstaConfiguration cfg = new CstaConfiguration(CSTA_SERVER_IP_ADDRESS, CSTA_SERVER_PORT);  // The CSTA Server IP and Port for HTTP/SOAP connection might be different than TCP connection

// Please refer to OpenScape Voice Server settings.

       cfg.setTransportType(CstaTransports.HTTP_SOAP); // Set Transport Type to HTTP_SOAP

       cfg.setListenerURL(localIP);                    // Set Local URL to listen for events

       cfg.setLocalPort(localPort);                    // Set Local Port to listen for events. Default is 80

       cfg.setMaxHttpConnections(15);                  // Set Max number of HTTP connections to OpenScape Voice Server

cfg.setKeepAlive(true);                         // Set keep alive or not. If set to true, CSTA-SDK will send RequestSystemStatus request every 2 minutes by default

 

 

Key concept: You need to keep this provider object around for the lifetime of the application (or until you decide to disconnect from OpenScape Voice). All requests we will do from now on will go through that provider object.

Once we have the connection we can monitor a device. This is done in the startMonitor function in CstaDeviceMonitor.java .

Since we want to receive CSTA events in the CstaDeviceMonitor class, we need to implement the CstaEventListener interface:

   public class CstaDeviceMonitor implements CstaEventListener               

 

With that in place, we can start the monitor and register it as an event listener. The two key function calls are highlighted bellow.

                  

  public class CstaDeviceMonitor implements CstaEventListener

  {

  ...

     public boolean startMonitor(CstaProvider provider, String device)

     {

        CstaDevice myDevice = provider.addDevice(device);

        try

        {

           monitor = provider.MonitorStart(myDevice);

           provider.registerEventListener(this);

           System.out.println("\n---\nStarted monitoring " + monitor.fqnDn + "\n---\n");

           return true;

        }

        catch (CstaException e)

        {

           System.err.println("Failed to start monitor: " + e.toString());

           return false;

        }

     }

 

Key concept: when an event arrives from OpenScape Voice, the CSTA SDK will parse it and call the newCstaEvent function from the CstaDeviceMonitor class

 
 

  public class CstaDeviceMonitor implements CstaEventListener

  {

  ...

     @Override

     public void newCstaEvent(CstaEventObject evt)

     {

        System.out.print("\n--- Device " + evt.fqnDN + " received event: type=" + evt.evtType

              + ", callID=" + evt.callID + "\n");

     }
  }
 
 

Key concept: the object that implements the event listener has to be kept around for as long as the application wants to monitor that device.

 

In our application we do that by simply hanging on to the object after we create it, as shown in the highlighted code below. In a more sophisticated application you may need to implement a list or map of all the devices being monitored.

Key concept: avoid adding any processing that it is resource intensive inside the CstaEventListner method. This method should be used only to get the notifications of CSTA messages, and extra processing should be done outside of the scope of this method.

 
 

  public class CstaMonitorMain

  {

  ...

     public static void main(String[] args)

     {

        CstaProvider myProvider = connect();

        if (myProvider != null)

        {

           CstaDeviceMonitor monitor = new CstaDeviceMonitor();

           if (monitor.startMonitor(myProvider, DEVICE_TO_MONITOR))

           {

              // Let it run until the user hits the enter key

              Scanner keyIn = new Scanner(System.in);

              System.out.print("\n\nPress Enter to exit\n\n");

              keyIn.nextLine();

Once the user hits the Enter key we reverse the steps we did above:

  • Stop monitoring
  • Disconnect from OpenScape Voice

The steps need to be done in reverse order.

This is done in this piece of code:

  public static void main(String[] args)

  {

      ...

           monitor.stopMonitor(myProvider);

        }

        disconnect(myProvider);

     }

  }      
 
            

The source code for the monitoring example

 

CstaMonitorMain.java

import java.util.Scanner;

 

import com.sen.openscape.csta.provider.CstaProvider;

import com.sen.openscape.csta.util.CstaConfiguration;

import com.sen.openscape.csta.util.CstaException;

 

public class CstaMonitorMain

{

   /**

    * The IP address of the CSTA interface in OpenScape Voice

    */

   private static final String CSTA_SERVER_IP_ADDRESS = "172.20.34.70";

 

   /**

    * The port number - it's usually 1040, very rarely changed

    */

   private static final int    CSTA_SERVER_PORT       = 1040;

 

   /**

    * The phone number we will monitor Must match the configured in OSV and must

    * have CSTA service assigned

    */

   private static final String DEVICE_TO_MONITOR      = "15619231972";

 

   public static void main(String[] args)

   {

      CstaProvider myProvider = connect();

      if (myProvider != null)

      {

         CstaDeviceMonitor monitor = new CstaDeviceMonitor();

         if (monitor.startMonitor(myProvider, DEVICE_TO_MONITOR))

         {

            // Let it run until the user hits the enter key

            Scanner keyIn = new Scanner(System.in);

            System.out.print("\n\nPress Enter to exit\n\n");

            keyIn.nextLine();

 

            monitor.stopMonitor(myProvider);

         }

         disconnect(myProvider);

      }

   }

 

   private static CstaProvider connect()

   {

      CstaConfiguration cfg = new CstaConfiguration(CSTA_SERVER_IP_ADDRESS, CSTA_SERVER_PORT);

      try

      {

         CstaProvider provider = new CstaProvider();

         provider.connectToSystem(cfg);

         System.out.println("\n---\nConnected to " + CSTA_SERVER_IP_ADDRESS + "\n---\n");

         provider.startHeartbeat(60, 60);

         return provider;

      }

      catch (CstaException e)

      {

         System.err.println("Failed to connect: " + e.toString());

         return null;

      }

   }

 

   private static void disconnect(CstaProvider provider)

   {

      try

      {

         provider.endHeartbeat();

         provider.disconnectFromSystem();

         System.out.println("\n---\nDisconnected from " + CSTA_SERVER_IP_ADDRESS + "\n---\n");

      }

      catch (CstaException e)

      {

         System.err.println("Failed to disconnect: " + e.toString());

      }

   }

 

}

 
 

CstaDeviceMonitor.java

import com.sen.openscape.csta.callcontrol.CstaDevice;

import com.sen.openscape.csta.callcontrol.CstaMonitor;

import com.sen.openscape.csta.provider.CstaEventListener;

import com.sen.openscape.csta.provider.CstaEventObject;

import com.sen.openscape.csta.provider.CstaProvider;

import com.sen.openscape.csta.util.CstaException;

 

public class CstaDeviceMonitor implements CstaEventListener

{

   private CstaMonitor monitor;

 

   public boolean startMonitor(CstaProvider provider, String device)

   {

      CstaDevice myDevice = provider.addDevice(device);

      try

      {

         monitor = provider.MonitorStart(myDevice);

         provider.registerEventListener(this);

         System.out.println("\n---\nStarted monitoring " + monitor.fqnDn + "\n---\n");

         return true;

      }

      catch (CstaException e)

      {

         System.err.println("Failed to start monitor: " + e.toString());

         return false;

      }

   }

 

   public void stopMonitor(CstaProvider provider)

   {

      try

      {

         provider.MonitorStop(monitor.crossRefId);

         System.out.println("\n---\nStopped monitoring " + monitor.fqnDn + "\n---\n");

         provider.removeDevice(monitor.fqnDn);

      }

      catch (CstaException e)

      {

         System.err.println("Failed to stop monitor: " + e.toString());

      }

   }

 

   @Override

   public void newCstaEvent(CstaEventObject evt)

   {

      System.out.print("\n--- Device " + evt.fqnDn + " received event: type=" + evt.evtType

            + ", callID=" + evt.callID + "\n");

   }

}

 
 

Developing a CSTA application to control calls

 

In this section we will not only monitor the device, but also act on calls arriving on that device.

We will implement a simple call router: when the application is active, any call that arrives at the device we are monitoring will be immediately be deflect to another device when the monitored Device is ringing.

The example will illustrate two items:

  • How to execute CSTA requests using the SDK
  • The considerations for performance: do as little as possible inside the CSTA event handler

 

This section assumes that you completed the device monitor tutorial. If you haven't completed it yet, please go over that section first. The example in this section builds on top of the monitor example.

Creating the project and adding the Java files

Create the project

Create a new project and set it up as explained in this section. Name that project CstaCallRouter.

Add three Java classes to the project

CstaCallRouterMain

CstaCallRouter

DeflectExecutor

 

 

At this point the project will look like this in eclipse:

 
image002
 

Adding the code

 

As in the previous example, don't worry about understanding the code at this point. We will go over the important pieces later.

Add the code for CstaCallRouterMain

Copy the code from this section and paste it into the CstaCallRouterMain.java file.

Add the code for CstaCallRouter

Copy the code from this section and paste it into the CstaCallRouter.java file.

Add the code for DeflectExecutor

Copy the code from this section and paste it into the DeflectExecutor.java file.

 

Customizing the code for your environment

 

Update the address of the CSTA signaling manager to point to your OpenScape Voice

Change the constant CSTA_SERVER_IP_ADDRESS to the IP address of the CSTA signaling manager in your environment. If you don't the address, ask the administrator of that OpenScape Voice system.

Update the phone number you will monitor

The number in the code must match exactly the FQN (e.g. +15619231000) of the number what is configured in the OpenScape Voice. 

This must be a phone that has the CSTA service assigned to it in OpenScape Voice.

Note that there is also a constant for the CSTA signaling manager port number (CSTA_SERVER_PORT). There is rarely a need to change the port number. It's here for completeness only.

Update the phone number where you will deflect the call

 

In addition to the IP address of the CSTA signaling manager and the monitored device that we had to customize in the previous example, we have to customize one more piece of information: the new destination for the call.

This new destination must be a dialable number in OpenScape Voice. In other words, if you go to the monitored device and enter that number, the call must complete. If it doesn't, the example will fail (the call will be not be deflected).

 

The highlighted text below shows the places that need to be adapted to your environment:

 

 

public class CstaCallRouterMain

{

   /**

    * The IP address of the CSTA interface in OpenScape Voice

    */

    private static final String CSTA_SERVER_IP_ADDRESS = "ip address goes here";

 

   /**

    * The port number - it's usually 1040, very rarely changed

    */

   private static final int CSTA_SERVER_PORT = 1040;

 

   /**

    * The phone number we will monitor

    * Must match the configured number in OSV and must have CSTA service assigned

    */

   private static final String DEVICE_TO_MONITOR      = "phone number goes here";

 

   /**

    * The new destination for incoming calls

    * Must be a dialable number in OSV

    */

   private static final String NEW_DESTINATION        = "new destination goes here"

}

 

Running the CstaCallRouter example

This example is also a command line Java application. We will follow it in the Console window of eclipse. If that window is not visible, select Window → Show View → Console to make it visible.

 

Before running the example, go to the phone that has the number being monitored and try to call the number in NEW_DESTINATION, exactly as you have it in the code. The call must ring there. If it doesn't, do not proceed with the example. It will fail. Check if the number is in the correct format and if the OpenScape Voice dial plan is correctly configured to dial that number.

 

Once you confirmed the number can be dialed, use the Run → Run menu option or click on the run button in the toolbar.

The first step of the example is the same as monitor example. The console will show the monitor steps:

 

...logs from the CSTA SDK
 
---
Connected to 172.20.34.70
---
 
... more logs from the CSTA SDK
 
---
Started monitoring 15619232315
 
---

 

 

Followed by the prompt to terminate the application:

 

Press Enter to exit

 

 

From this point on things are different.

 

Before you terminate the application:

  1. Make a call to the monitor number
  2. The call will ring in the number we have in NEW_DESTINATION

 

The console will show these logs (showing only the logs from the application - the CSTA SDK logs were removed to save space):

 

 

--- Scheduled the deflect request
...
 
--- Thread pool deflecting from +15619232315 to 32325
...
 
--- Device 15619232315 received event: type=DIVERTED, service ID=15619232315
...
 
--- Call was deflected

 

If the call wasn't deflected, check if there is another CSTA application already monitoring that device.

If that is the case, change the code to act on the DELIVERED event:

 

public void newCstaEvent(CstaEventObject evt)

{

   if (evt.evtType == CstaEventType.DELIVERED)

   {

 

The disadvantage of this approach is the splash ring (a short ring cycle) on the monitored device before the call is deflected. That is why we used the OFFERED event first. If you know your application is only one monitoring the device, the OFFERED event allows you to control the call before any device gets it.

 

Understanding the CstaCallRouter example code

The code has three main pieces:

  • Connect to the OpenScape Voice
  • Request to monitor a device
  • Deflect the call

The first two are the same as in the first example.

 

The third piece is new for this example. This is the one we will concentrate on in this section.

 

First we need to decide which event will trigger the deflect request. We used the DELIVERED event in this example and we are assuming our application is the only one monitoring that device:

 

  public void newCstaEvent(CstaEventObject evt)

  {

     if (evt.evtType == CstaEventType.DELIVERED)

     {

       

Once we know we got the DELIVERED event we can request the deflect to the new number.

Key concept: Do as little as possible inside the event handler. We must get out of the event handler code as fast as we can to allow the CSTA SDK to process more events. The CSTA SDK has a thread pool to process more than one event at the same time, but the thread pool is not infinite. Once all threads are busy with events, the next event will only be dispatched when one of the threads returns from the event handler function. An application that executes slow code inside the event handler will eventually force the CSTA SDK to hold back on event dispatching.

 

We will not execute the deflect request inside the event handler function. Our application has its own thread pool to execute the requests. It is all in the DeflectExecutor class.

 

First we need a thread pool:

 

public class DeflectExecutor

{

   /**

    * The thread pool to execute the deflection requests - adjust size as needed

    */

   private static final ExecutorService pool = Executors.newFixedThreadPool( 5 );

 

We chose five threads in our example because we are not monitoring many devices, so don't expect to get many events at the same time. If you are monitoring several devices, you need to increase the thread pool.

 

With the thread pool in place, we need a task to feed into it. Any class that implements the Runnable interface will do. This is the class that will execute the deflect request. It needs the connection to deflect and the new destination.

 

For this example we chose to implement it as an inner class. The users of the thread pool don't need to be aware of how exactly the request is processed. All they care about is that it will not be executed inside the event handler.

 

public class DeflectExecutor

{

...

   /**

    * The task added to the thread pool to execute the deflection request

    */

   private static class DeflectTask implements Runnable

   {

      private CstaConnection conn;

      String  newDestination;

     

      public DeflectTask( CstaConnection conn, String newDestination )

      {

         this.conn = conn;

         this.newDestination = newDestination;

      }

 

The deflection happens inside the run() function of DeflectTask:

 

public class DeflectExecutor

{

...

   private static class DeflectTask implements Runnable

   {

...

      public void run()

      {

         try

         {

            conn.DeflectCall(newDestination);

            System.out.print("\n--- Thread pool deflecting from " + conn.deviceID + " to " + newDestination + "\n\n");

         }

         catch (CstaException e)

         {

            System.err.print("\n--- ERROR: Deflect request failed: " + e.toString());

            e.printStackTrace();

         }

 

With all those pieces in place, the event handler can call the deflect function. A new task is created behind the scenes and added to the thread pool.

 

public class DeflectExecutor

{

...

   public static void deflect( CstaConnection conn, String newDestination )

   {

      pool.execute( new DeflectTask( conn, newDestination ) );

   }

 

And now we can see in the logs exactly what we want:

  • The event handler finishes quickly (the first log below)
  • The request is processed in the background, outside of the event handler (second log)

 

 

--- Scheduled the deflect request
...
 
--- Thread pool deflecting from +15619232315 to 32325
...

 

 

Key concept: Note that the deflection is executed on a CstaConnection object. That object identifies a specific call present on the device. Since a device can have more than one call present on it at any given time, we need to identify the call we want to act on. That is what the CstaConnection does

 

 

The CstaConnection object can be retrieved from the CstaMonitor object using a call ID. The call ID is sent in the event.

 

public class CstaCallRouter implements CstaEventListener

{

...

   public void newCstaEvent(CstaEventObject evt)

   {

      if (evt.evtType == CstaEventType.DELIVERED)

      {

         // Handover the deflect request to the thread pool

         // DO NOT execute any lengthy operation inside the event handle

         CstaConnection c = monitor.getConnectionByCallID(evt.callID);

         DeflectExecutor.deflect(c, deflectTo);

 

Finally, we need to test if the deflection worked. We we will receive a DIVERTED event when the call is redirected from the monitored device to the new destination.

 

In our simple application all we do is to check if there is no other call (connection) left in the monitored device. If so, the call was deflected successfully. On a more complex application we cannot assume that the device will have only one call at a time. We would need to keep track of each connection on the device and test if the one we attempted to deflect is gone. We would also need to monitor the new destination to make sure it got there (it could have failed to reach it for a number other reasons).

 

public class CstaCallRouter implements CstaEventListener

{

...

   public void newCstaEvent(CstaEventObject evt)

   {

...

      else

      {

         System.out.print("\n--- Device " + evt.fqnDn + " received event: type=" + evt.evtType

               + ", callID=" + evt.callID + "\n\n");

         if (evt.evtType == CstaEventType.DIVERTED)

         {

            // A quick test to find out if the deflect worked: if we get a DIVERTED event

            // and there is no connection on the device anymore, the deflect worked.

            // This is a simple-minded test - it assumes there was only one connection on that

            // device. In real life we need to remember which connection we tried to deflect

            // and check if it is still on that device.

            CstaConnection c = monitor.getConnectionByCallID(evt.callID);

            if (c == null)

            {

               System.out.print("\n--- Call was deflected\n\n");

            }

 

 

The source code for the CSTA Call Router example

 

 

CstaCallRouterMain.java

 

import java.util.Scanner;

 

import com.sen.openscape.csta.provider.CstaProvider;

import com.sen.openscape.csta.util.CstaConfiguration;

import com.sen.openscape.csta.util.CstaException;

import com.sen.openscape.csta.util.CstaTransports;

 

public class CstaCallRouterMain

{

   /**

    * The IP address of the CSTA interface in OpenScape Voice

    */

   private static final String CSTA_SERVER_IP_ADDRESS = "10.152.231.115";

 

   /**

    * The port number - it's usually 1040, very rarely changed

    */

   private static final int CSTA_SERVER_PORT = 1040;

 

   /**

    * The phone number we will monitor

    * Must match the configured number in OSV and must have CSTA service assigned

    */

   private static final String DEVICE_TO_MONITOR = "15619232315";

 

   /**

    * The new destination for incoming calls

    * Must be a dialable number in OSV

    */

   private static final String NEW_DESTINATION = "32325";

 

   public static void main(String[] args)

   {

      CstaProvider myProvider = connect();

      if (myProvider != null)

      {

         CstaCallRouter router = new CstaCallRouter();

         if (router.start(myProvider, DEVICE_TO_MONITOR, NEW_DESTINATION))

         {

            // Let it run until the user hits the enter key

            Scanner keyIn = new Scanner(System.in);

            System.out.print("\n\nPress Enter to exit\n\n");

            keyIn.nextLine();

 

            router.stop(myProvider);

         }

         disconnect(myProvider);

      }

   }

 

   private static CstaProvider connect()

   {

      CstaConfiguration cfg = new CstaConfiguration(CSTA_SERVER_IP_ADDRESS, CSTA_SERVER_PORT);

      cfg.setTransportType(CstaTransports.TCP);

      try

      {

         CstaProvider provider = new CstaProvider();

         provider.connectToSystem(cfg);

         System.out.println("\n---\nConnected to " + CSTA_SERVER_IP_ADDRESS + "\n---\n");

 

         provider.startHeartbeat(60, 60);

         return provider;

      }

      catch (CstaException e)

      {

         System.err.println("Failed to connect: " + e.toString());

         return null;

      }

   }

 

   private static void disconnect(CstaProvider provider)

   {

      try

      {

         provider.endHeartbeat();

         provider.disconnectFromSystem();

         System.out.println("\n---\nDisconnected from " + CSTA_SERVER_IP_ADDRESS + "\n---\n");

      }

      catch (CstaException e)

      {

         System.err.println("Failed to disconnect: " + e.toString());

      }

   }

 

}

 

 

 

CstaCallRouter.java

 

import com.sen.openscape.csta.callcontrol.CstaConnection;

import com.sen.openscape.csta.callcontrol.CstaDevice;

import com.sen.openscape.csta.callcontrol.CstaMonitor;

import com.sen.openscape.csta.provider.CstaEventListener;

import com.sen.openscape.csta.provider.CstaEventObject;

import com.sen.openscape.csta.provider.CstaEventType;

import com.sen.openscape.csta.provider.CstaProvider;

import com.sen.openscape.csta.util.CstaException;

 

public class CstaCallRouter implements CstaEventListener

{

   private CstaMonitor monitor;

   private String deflectTo;

 

   public boolean start(CstaProvider provider, String device, String newDestination)

   {

      deflectTo = newDestination;

      CstaDevice myDevice = provider.addDevice(device);

      try

      {

         monitor = provider.MonitorStart(myDevice);

         provider.registerEventListener(this);

         System.out.println("\n--- Started monitoring " + monitor.fqnDn + "\n\n");

         return true;

      }

      catch (CstaException e)

      {

         System.err.print("\n--- ERROR: MonitorStart failed: " + e.toString());

         e.printStackTrace();

         return false;

      }

   }

 

   public void stop(CstaProvider provider)

   {

      try

      {

         provider.MonitorStop(monitor.crossRefId);

         System.out.println("\n--- Stopped monitoring " + monitor.fqnDn + "\n\n");

         provider.removeDevice(monitor.fqnDn);

      }

      catch (CstaException e)

      {

         System.err.println("Failed to stop monitor: " + e.toString());

      }

   }

 

   @Override

   public void newCstaEvent(CstaEventObject evt)

   {

      if (evt.evtType == CstaEventType.DELIVERED)

      {

         // Handover the deflect request to the thread pool

         // DO NOT execute any lengthy operation inside the event handle

         CstaConnection c = monitor.getConnectionByCallID(evt.callID);

         DeflectExecutor.deflect(c, deflectTo);

         System.out.println("\n--- Scheduled the deflect request\n\n");

      }

      else

      {

         System.out.print("\n--- Device " + evt.fqnDn + " received event: type=" + evt.evtType

               + ", callID=" + evt.callID + "\n\n");

         if (evt.evtType == CstaEventType.DIVERTED)

         {

            // A quick test to find out if the deflect worked: if we get a DIVERTED event

            // and there is no connection on the device anymore, the deflect worked.

            // This is a simple-minded test - it assumes there was only one connection on that

            // device. In real life we need to remember which connection we tried to deflect

            // and check if it is still on that device.

            CstaConnection c = monitor.getConnectionByCallID(evt.callID);

            if (c == null)

            {

               System.out.print("\n--- Call was deflected\n\n");

            }

         }

      }

   }

}

 

 

 

DeflectExecutor.java

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

import com.sen.openscape.csta.callcontrol.CstaConnection;

import com.sen.openscape.csta.util.CstaException;

 

public class DeflectExecutor

{

   /**

    * The thread pool to execute the deflection requests - adjust size as needed

    */

   private static final ExecutorService pool = Executors.newFixedThreadPool( 5 );

  

   /**

    * The interface to the users of this class

    * The fact have a thread pool is hidden from them - all they care about is to execute the task

    */

   public static void deflect( CstaConnection conn, String newDestination )

   {

      pool.execute( new DeflectTask( conn, newDestination ) );

   }

 

   /**

    * The task added to the thread pool to execute the deflection request

    */

   private static class DeflectTask implements Runnable

   {

      private CstaConnection conn;

      String  newDestination;

     

      public DeflectTask( CstaConnection conn, String newDestination )

      {

         this.conn = conn;

         this.newDestination = newDestination;

      }

 

      public void run()

      {

         try

         {

            conn.DeflectCall(newDestination);

            System.out.print("\n--- Thread pool deflecting from " + conn.deviceID + " to " + newDestination + "\n\n");

         }

         catch (CstaException e)

         {

            System.err.print("\n--- ERROR: Deflect request failed: " + e.toString());

            e.printStackTrace();

         }

      }

   }

}