PresenceMonitor-Csharp - Wiki
Wiki
PresenceMonitor-Csharp
About the Application#
This application will be triggered by an incoming HTTP request. Once the application is triggered, it will subscribe to the Presence service and will update the App-Server of the status of a Presentity until it is not Unsubscribed from the Presence service.
Using this application one can subscribe to as well as unsubscribe from the Presence service.
Create the Application Project#
1. Open a Command Prompt window.
2. Navigate to the directory you want to use as your workspace. To use the CUAE command-line tool to create a new application, type the cuae create command and the name of the application project.
C:\> cd WxpC:\Wxp>cuae create PresenceMonitor}}}
The tool then prompts you for additional information.
Note: Once you are more familiar with the options, you can type the full command rather than answering the prompts by using the following syntax://
cuae create -l language -m namespace -t project type [options] projectname
cuae create -l csharp -m PresenceMonitor -t app PresenceMonitor
3. First the tool prompts you to choose between building an application or a plugin. In this example, the correct choice is application:
Project type? [application or plugin] application
4. Next the tool prompts you to specify the programming language. In this example, the correct choice is java:
Programming language? [java or csharp] csharp
5. The tool asks you for the namespace for the application. A Java program might want to use a fully qualified namespace like com.company.presencemonitor or something simple like presencemonitor. The tool offers you a simple namespace based on the project name. Let's accept the tool's suggestion for now and use presencemonitor:
Project namespace? [default: presencemonitor] <return>
7. Finally, the tool asks if you would like to specify a triggering event. All applications need to register against at least one triggering event. You can specify the triggering event now or wait and specify the triggering event later. You can also change the triggering event during development. Again, since we know that this application needs to be triggered on an HTTP request, let's go ahead and specify the triggering event now. Select option 5:
Available application triggering event:0: Skip this step 1: cisco.uc.cuae.legacy.JTapi.JTapiIncomingCall 2: cisco.uc.cuae.legacy.JTapi.JTapiCallInitiated 3: cisco.uc.cuae.legacy.JTapi.JTapiCallEstablished 4: cisco.uc.cuae.legacy.CallControl.IncomingCall 5: cisco.uc.cuae.legacy.Http.GotRequest 6: cisco.uc.cuae.legacy.Presence.SubscriptionTerminated 7: cisco.uc.cuae.legacy.Presence.Notify 8: cisco.uc.cuae.legacy.TimerFacility.TimerFire Triggering event? [0-8] 5}}}
The tool now has enough information to generate the project template.
Generating:
- application named "PresenceMonitor"
- with namespace "presencemonitor"
- with laguage "csharp"
- with trigger event "cisco.uc.cuae.legacy.Http.GotRequest"
- in location C:\Wxp\
Created project "PresenceMonitor" in directory "C:\Wxp\PresenceMonitor\" }}}
Here is the whole sequence again with all the pieces together:
C:\>cd WxpC:\Wxp>cuae create PresenceMonitor Project type? [application or plugin] Application Programming language? [java or csharp] csharp Project namespace? [default: presencemonitor] Available application triggering event: 0: Skip this step 1: cisco.uc.cuae.legacy.JTapi.JTapiIncomingCall 2: cisco.uc.cuae.legacy.JTapi.JTapiCallInitiated 3: cisco.uc.cuae.legacy.JTapi.JTapiCallEstablished 4: cisco.uc.cuae.legacy.CallControl.IncomingCall 5: cisco.uc.cuae.legacy.Http.GotRequest 6: cisco.uc.cuae.legacy.Presence.SubscriptionTerminated 7: cisco.uc.cuae.legacy.Presence.Notify 8: cisco.uc.cuae.legacy.TimerFacility.TimerFire Triggering event? [0-8] 5 Generating:
- application named "PresenceMonitor"
- with namespace "presencemonitor"
- with laguage "csharp"
- with trigger event "cisco.uc.cuae.legacy.Http.GotRequest"
- in location C:\Wxp\
Created project "PresenceMonitor" in directory "C:\Wxp\PresenceMonitor\" }}}
Inspecting the Generated Project#
Let's inspect the files that were generated by the CUAE command-line tool. It created a PresenceMonitor directory in the directory from which you ran the cuae create command. The PresenceMonitor directory contains the following files and directories:
- PresenceMonitor.etch
- PresenceMonitor.properties
- PresenceMonitor.csproj
- cuae-resources/
- README.txt
- src/
The most important of which, for your purposes, are:
- PresenceMonitor.etch--CUAE application Etch service definition. Edit this file to use additional CUAE services in your project.
- PresenceMonitor.csproj--Visual Studio csproject file with predefined targets for managing the lifecycle of your CUAE project.
- cuae-resources/--CUAE application resource directory.
- src/--Generated application source files.
Declaring Services#
The first step in building an Etch-based application is identifying which Cisco Unified Application Environment hosted services the application requires and then editing the .etch file to declare the names of those services into the application.
Note: Once you identify the services you need, you can familiarize yourself with them by visiting the API reference for the version of the Unified Application Environment you are using.
The following snippet is the default content of the .etch file that the CUAE command-line tool generates. We use the mixin command to declare the appropriate services.
// CUAE Application Etch Service Definition
//
// This service defines your application and the CUAE services that you
// use in your application.
// The service module namespace, this will be translated to the
// namespace of the generated source code.
module presencemonitor
// The name of your service.
service PresenceMonitor
{
// By default, you must always use the EtchBridge service. Do not
// remove this mixin, otherwise your application won't work.
mixin cisco.uc.cuae.EtchBridge
// You may add any additional service mixins that you require. For
// example, if you'd like to make and receive phone calls, add the
// following line:
// mixin cisco.uc.cuae.legacy.CallControl
mixin cisco.uc.cuae.legacy.Http
}Because this application will handle an incoming HTTP request and subscribe a user to the Presence service, we need to utilize the HTTP and Presence services. The default etch file already has a mixin for HTTP because of the triggering event you selected when creating the application project.
mixin cisco.uc.cuae.legacy.Http
We need to add a declaration for the Presence service, using the full namespace. Add the following line right after the mixin for HTTP but before the final "}":
mixin cisco.uc.cuae.legacy.Presence
The new PresenceMonitor.etch file should look like this:
// CUAE Application Etch Service DefinitionThis service defines your application and the CUAE services that you use in your application.
The service module namespace, this will be translated to the namespace of the generated source code. module presencemonitor
The name of your service.service PresenceMonitor{ By default, you must always use the EtchBridge service. Do not remove this mixin, otherwise your application won't work.mixin cisco.uc.cuae.EtchBridge
You may add any additional service mixins that you require. For example, if you'd like to make and receive phone calls, add the following line: mixin cisco.uc.cuae.legacy.CallControl mixin cisco.uc.cuae.legacy.Http mixin cisco.uc.cuae.legacy.Presence } }}}
Building the Application#
After declaring the services you need, you must build the application to generate source files.
1. Open a Command Prompt and navigate to the application directory.
2. Run the msbuild command to generate source files.
C:\Wxp>cd PresenceMonitorC:\Wxp\PresenceMonitor>msbuild}}}
The following source file templates are then created in the directory src\presencemonitor:
- MainPresenceMonitorClient.cs
- ImplPresenceMonitorClient.cs
Creating Configuration Items#
YAML is the file format for Unified Application Environment application configuration (config.yaml) and metadata definitions project_name.yaml).
All application configuration items are written in the config.yaml file, which is located in the cuae-resources directory.
Configuration items follow a specific syntax, as follows.
-name:[display name:] format: [description:] [minvalue:] [maxvalue:] [defaultvalue:] [readonly:] [required] }}}
- Items in square brackets [] are optional
The default config.yaml file contains the following information:
# CUAE Application Configuration Definition
- You only need to edit this file if you want to expose configuration to
- the administrator through cuaeadmin.
- This file was auto-generated from a template but will never be
- overwritten. You should edit this file directly if required.
configuration:
- Indicates the name of your configuration item. It will be how you
- reference this configuration item from code.
- - name: myConfValue
- Controls how the visible label of the configuration value. For
- example, if 'name' was defined as: myConfValue, you may choose to
- define 'displayName' as: My Config Value. Think of it as a friendly
- name. This field is optional.
- displayName: My Config Value
- Defines the format of the configuration item's value. This will
- control how cuaeadmin renders and validates the value. Possible
- values for the 'format' field are: String, Bool, Number, IP_Address,
- Array, HashTable, Password.
- format: String
- A description of the configuration item that will be displayed to
- the administrator in cuadmin. This field is optional.
- description: Some description here.
- For configuration items that are formatted as numbers, the
- 'minValue' and 'maxValue' configuration items define the acceptable
- range of input for the item. These fields are optional.
- minValue:
- maxValue:
- Defines the default value of the configuration. This field is
- optional.
- defaultValue:
- Inidicates whether the configuration item is editable. If
- 'readOnly' is set to true, the administrator will not be able to
- edit it in cuaeadmin, but will be able to view it. The default is
- false, and this field is optional.
- readOnly:
- Indicates whether the configuration item is required. If required,
- the administrator will have to set a value before the application
- will run. The default is false, and this field is optional.
- required: false }}}
In this example, the application has four configuration items, the user to be subscribed, password for the user to be subscribed, the Request URI for which the Presence status is to be fetched and the type of action. Add the following block to the config.yaml file in the configuration section:
configuration:- name: Subscriber displayName: Subscriber format: String defaultValue:
- name: Password displayName: Password format: String defaultValue:
- name: StringUri displayName: StringUri format: String defaultValue:
- name: Action displayName: Action[NTS|U] format: String defaultValue: }}}
Writing Application Code#
This section provides instructions and code samples for writing the application logic.
Import the Project into Microsoft Visual Studio#
1. Open Microsoft Visual Studio.
2. Open the PresenceMonitor.csproj file by selecting File -> Open -> Project/Solution and browsing to the directory C:\Wxp\PresenceMonitor.
Reading Application Configurations#
The CUAE application receives the current application configurations from CUAE server using method server.getConfig("partition name") in gotRequest event handler in the ImplPresenceMonitorClient.java file. The developer can iterate through the configurations array and parse the configuration item based on its type.
Handle the onGotRequest triggering event#
You should write a method to handle the event of the onGotRequest trigger to subscribe a user to the presence server and send a response back to the device which has initiated the HTTP request.
Code Sample#
Note: Insert the below given code sample in the ImplPresenceMonitorClient.cs file below the // TODO line.
// TODO: Implement delegates or provide implementation of PresenceMonitorClientmessages from the server
Defining the global variables to collect the configuration itemsprivate String subscriber = "";private String password = "";private String requestUri = "";private String action = "";
public override void gotRequest(string sessionId, cisco.uc.cuae.legacy.types.Http.GotRequestOptions options) { Getting the configuration items set by the usertry {ConfigEntry[] aConfigs = server.getConfig("Default");if (aConfigs != null && aConfigs.Length > 0){for (int i=0; i<aConfigs.Length; i++){if (aConfigs[i].name.Equals("Subscriber")) {subscriber = aConfigs[i].configValue.ToString();Console.WriteLine("Subscriber : " + subscriber);}if (aConfigs[i].name.Equals("Password")) {password = aConfigs[i].configValue.ToString();Console.WriteLine("Password : " + password);}if (aConfigs[i].name.Equals("StringUri")) {requestUri = aConfigs[i].configValue.ToString();Console.WriteLine("String URI : " + requestUri);}if (aConfigs[i].name.Equals("Action")) {action = aConfigs[i].configValue.ToString();Console.WriteLine("Action : " + action);}}}}catch (cisco.uc.cuae.types.EtchBridge.BridgeException err){Console.WriteLine("Failed to retrieve configs: " + err.ToString());server.removeCuaeSession(sessionId);return;}
String actionStatus = "";
if (action == "NTS") { Console.WriteLine("NTS recieved"); actionStatus = server.nonTriggeringSubscribe(sessionId, requestUri, subscriber, password, null).resultCode.ToString(); Console.WriteLine("NonTriggeringSubscribe executed successfully"); String response = "Action status: " + actionStatus + "received for action:" + action; server.sendResponse(sessionId, options.remoteHost, 200, "text/plain", response, "OK", null); }
else if (action == "U") { Console.WriteLine("U Recieved"); actionStatus = server.unsubscribe(sessionId, requestUri, subscriber, password, true, null).resultCode.ToString(); Console.WriteLine("Unsubscribe executed successfully"); String response = "Action status: " + actionStatus + "received for action:" + action; server.sendResponse(sessionId, options.remoteHost, 200, "text/plain", response, "OK", null); server.removeCuaeSession(sessionId); }
} }}}
Handle the onNotify triggering event#
Once the user is subscribed to the Presence server, the Presence server will start sending notification messages to the App-server. You need to write a method to handle the onNotify event.
Code Sample#
public override void notify(string sessionId, NotifyOptions options){
String status = options.status;
String status1 = status.Substring(status.IndexOf("<presence"));
String current = status1.Substring(status1.IndexOf("id=") + 4);
try { String name = current.Substring(0, current.IndexOf("\""));
current = (current.Substring(current.IndexOf("<activities") + 1)); current = current.Substring(current.IndexOf("<") + 1); extract activityString activity = current.Substring(0, current.IndexOf(" "));
check if away or busy as they end with "/>" instead of a " "if (activity.Contains("/>"))activity = activity.Substring(0, activity.IndexOf("/"));
Console.WriteLine("The user: " + name + "is: " + activity); } catch (Exception e) { Console.WriteLine("The status of the contact for user could not be retrieved. Error message:" + e.ToString()); } } }}}
Note: Just check that the below given namespaces are being used.
using cisco.uc.cuae.types.EtchBridge;
using cisco.uc.cuae.legacy.types.Http;
using cisco.uc.cuae.legacy.types.Presence;
using presencemonitor.types.PresenceMonitor;
Handle the onSubscriptionTerminated event#
Subscription for a particular user is terminated by the Presence server on the basis of the values configured in the Presence server and the Presence provider in the App-server for subscription termination. Once the subscription is terminated an event is triggered at the App-server. You need to handle this event.
Code Sample#
public override void subscriptionTerminated(string sessionId, SubscriptionTerminatedOptions options){ server.logWrite(LogLevel.INFO, "Subscription terminated: " + options.requestUri + " - " + options.subscriber); server.removeCuaeSession(sessionId); } }}}
Handle the onSessionExpired event#
An HTTP session is terminated after a stipulated time. Once the HTTP session is expired you need to handle this event.
Code Sample#
public override void sessionExpired(string sessionId, cisco.uc.cuae.legacy.types.Http.SessionExpiredOptions options){ server.removeCuaeSession(sessionId); } }}}
Registering the Application#
The previous steps completed the core logic of the example applications, but before any Etch-based API actions can actually be used, we must register the application with the Cisco Unified Application Server. To register your application, follow these steps:
1. Open the MainPresenceMonitorClient file in the /src directory. It contains the following content by default:
// This file automatically generated by:0.96.0 (ETCH-TRUNK-906) / csharp 0.96.0 (ETCH-TRUNK-906) Tue Aug 12 11:24:12 IST 2008
using System;
using presencemonitor.types.PresenceMonitor;
namespace presencemonitor { /<summary>Main implementation for PresenceMonitorClient.</summary>public class MainPresenceMonitorClient : PresenceMonitorHelper.PresenceMonitorClientFactory{/<summary>Main for PresenceMonitorClient</summary> /<param name="args">Command Line Arguments</param>public static void Main(String[] args){ TODO: Change to correct URI string uri = "tcp://localhost:4001";
RemotePresenceMonitorServer server = PresenceMonitorHelper.NewServer( uri, null, new MainPresenceMonitorClient());
Connect to the serviceserver._StartAndWaitUp( 4000 );
TODO: Insert Your Code Here
Disconnect from the serviceserver._StopAndWaitDown( 4000 ); }
/<summary>Return a new instance of PresenceMonitorClient.</summary>/<param name="server">Reference to remote service</param> /<returns>Client Implementation</returns>public PresenceMonitorClient NewPresenceMonitorClient( RemotePresenceMonitorServer server ){return new ImplPresenceMonitorClient( server );}} } }}}
2. To make a connection to the listener, add a server.registerApplication() request.
// TODO: Insert Your Code HereString key = server.registerApplication("PresenceMonitor", "Default", "<user-id>", "<password>"); Console.WriteLine("PresenceMonitor registered: " + key); Console.WriteLine("Press any key to exit ..."); Console.ReadLine(); }}}
3. Modify the String URI to match the IP address and port of the Cisco Unified Application Server.
URI settings vary slightly between 2.5(1) Beta 1 and more recent versions of 2.5(1), as follows: