Extending Unified Communications Services of UCMA Bots to PIC Clients: Creating Application Project (Part 4 of 5)

Summary:   Learn how to extend Microsoft Lync Server 2010 supported unified communications services that are provided by a trusted Microsoft Unified Communications Managed API (UCMA) bot application to Public Internet Cloud (PIC) clients. Without the extension, the unified communications services are restricted to a limited number of Microsoft Lync 2010 clients in a single enterprise network domain. This number is derived from the CategorySubscriptions property of the presence policy that is set by a Lync Server 2010 administrator. Here, PIC clients can include Windows Live Messenger, Skype, and Yahoo! Messenger.

Programmatically, you learn how to enable a Lync Server 2010 application by using the Microsoft Lync Server 2010 SIP Application API and UCMA. Lync Server 2010 SIP Application API is used to intercept a presence subscription from a PIC client and UCMA is used to send the requesting PIC client the online status of an active bot.

Applies to:   Microsoft Unified Communications Managed API (UCMA) 3.0 Core SDK | Microsoft Lync Server 2010 SDK

Published:   May 2012 | Provided by:   Kurt De Ding and Ajay Soni, Microsoft | About the Author

Contents

  • Creating a Complete Application Project

  • Instantiating and Initializing Application Endpoints Manager

  • Initializing SIP Application API Application

  • Processing Intercepted Messages in an Event Handling Loop

  • Additional Resources

Download code  Download code

This is the fourth in a series of five articles about how to extend the services of a Microsoft Unified Communications Managed API (UCMA) bot application to Public Internet Cloud (PIC) clients by enabling an unlimited number of PIC clients that can subscribe to the presence of the UCMA bot.

Creating a Complete Application Project

The following tasks are discussed in part 1 through part 3.

  • How a Microsoft SIP Processing Language (MSPL) script intercepts the presence SUBSCRIBE request by a PIC client and forwards it to a managed event handler.

  • How the managed event handler parses the request to determine whether the request is targeted at an enabled bot and is non-terminating.

  • How the managed application accepts the request with a 200 OK response and returns the bot’s Online status to the PIC client.

  • How to forward the request back to the server if the request is not accepted.

To make them work together, the managed application must maintain a list of currently enabled bots in a separate thread, obtain a SipPeerToPeerEndpoint object for the application, send the PIC client a NOTIFY message on behalf of the bot, and connect to the Microsoft Lync Server 2010 computer so that received events that are requested can be dispatched from the compiled MSPL script. Because the maintenance of enabled bots and the event dispatching must be run at the same time, they have to be executed in separate threads. In part 4, the following tasks are discussed.

  1. Provision a SipPeerToPeerEndpoint object that represents the Microsoft Lync Server 2010 SIP Application API application and start the process to enumerate enabled bots in a background thread.

  2. Load the compiled application manifest and connect the Lync Server 2010 SIP Application API application to a Lync Server 2010 computer to obtain a ServerAgent object.

  3. Process intercepted SIP message in an event-handling loop.

Instantiating and Initializing Application Endpoints Manager

Because the application uses the Lync Server 2010 SIP Application API and UCMA, you should group the usage of the two APIs into two separate classes. The first encapsulates features supported by the Lync Server 2010 SIP Application API and the second group is set up for UCMA. This kind of separation facilitates feature management and helps highlight the roles of the different APIs in an application.

In the accompanying application project, the AppEndpointManager class is used to implement UCMA-supported features. This class implements the following main features:

  1. Creates a SipPeerToPeerEndpoint instance to represent the Lync Server 2010 application so that the application can send a bot’s presence status directly to a requesting PIC client. The implementation is shown in the CreateP2PEndpoint method that appears in the next example.

  2. Dispatches the Online presence status of a bot to a PIC client by sending a NOTIFY message that contains a PDIF document as the payload. For more information, see the SendBotsOnlineStatusToPicClient method that appears in Extending Unified Communications Services of UCMA Bots to PIC Clients: Handling SUBSCRIBE Requests (Part 3 of 5).

  3. Maintains all currently enabled bots so that the presence status of any cached bot is online (or open) and any bot not in the cache is classified as offline (or closed). The implementation is shown in the StartBotsChecker method that appears in the next code example.

To create a UCMA endpoint and connect it to a Lync Server 2010 computer, an application must specify the appropriate configuration information for the application. This information, also known as the application endpoint settings, includes the SIP URI of the application endpoint and required security context, and also the IP address of the server and the port number of the application. This information is required to establish connections between the endpoint and the server. As shown in the next code example, for a trusted application such as the Lync Server 2010 application that is discussed in this article, the application endpoint settings are automatically provisioned if the CollaborationPlatform class is instantiated by using a ProvisionedApplicationPlatformSettings object. To receive the application endpoint settings through auto-provisioning, the application must implement an event handler to receive application endpoint settings, and then register the event handler with the CollaborationPlatform object by calling the RegisterForApplicationEndpointSettings(EventHandler<ApplicationEndpointSettingsDiscoveredEventArgs>) method before the CollaborationPlatform object is created.

void CreateP2PEndpoint()
{
    Console.WriteLine("Creating P2P Endpoint...for {0}", _appID);
    try
    {
        if (!string.IsNullOrEmpty(_appID))
        {
            Console.WriteLine(
                  "Creating CollaborationPlatform for the provisioned application with "
                + "ID \'{0}\' using ProvisionedApplicationPlatformSettings.", _appID);

            ProvisionedApplicationPlatformSettings settings = new
                ProvisionedApplicationPlatformSettings("PresenceSubInterceptor", _appID);
            _collabPlatform = new CollaborationPlatform(settings);
            // Receive applicationEndpoint settings through auto-provisioning
            _collabPlatform.RegisterForApplicationEndpointSettings(ApplicationEndpointSettingsDiscovered);
            _collabPlatform.EndStartup(_collabPlatform.BeginStartup(null, null));

            Console.WriteLine("platform started.");
        }
        else
        {
            Console.WriteLine("Error: Application ID not provided.");
        }
    }
    catch (Exception iOpEx)
    {
        Console.WriteLine(iOpEx.ToString());
    }
}

When auto-provision is used, the application has to provide the application ID that is used to enable the application as a trusted application with a trusted application endpoint. When specified in the application’s configuration file, the application ID can be read at the run time. The following example shows an example of this kind of application configuration file. In the accompanying sample application project, this configuration is named PresenceSubInterceptorForBot.exe.config. For more information about how to activate a trusted application, see Extending Unified Communications Services of UCMA Bots to PIC Clients: Building and Deploying Application (Part 5 of 5).

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="ApplicationID" value="urn:application:presencesubinterceptorforbot"/>
    <add key="DisableHeaderValidationForSendMessage" value="true" />
  </appSettings>
</configuration>

In addition to specifying the ApplicationId value, the configuration file also contains a specification of the DisableHeaderValidationForSendMessage property. This property is intended to be read by using UCMA. If it is true, UCMA will disable header validation when a message is sent. This allows the application to send a message as part of an ongoing dialog between the client and the bot. Otherwise, header validation will be enabled and exceptions are thrown when the application adds the restricted Call-Id and CSeq headers to a NOTIFY message to dispatch the online status of the bot to a requesting PIC client.Initializing the application endpoint manager involves reading the application configuration, creating the endpoint, and starting the process to poll available bots. As shown in the next example, these tasks can be invoked in the constructor of the AppEndpointManager class.

public AppEndpointManager()
{
    ReadAppConfig();
    CreateP2PEndpoint();
    StartBotsChecker();
}

An implementation of the ReadAppConfig method appears in the next example.

void ReadAppConfig()
{
    // Read the PresenceSubInterceptorForBot.exe.Config file for ApplicationID value.
    if (ConfigurationManager.AppSettings["ApplicationID"] != null)
    {
        _appID = ConfigurationManager.AppSettings["ApplicationID"];
        Console.WriteLine(String.Format("_appID: {0}", _appID));
    }
}

In the following example, an implementation of StartBotsChecker shows how to create a separate thread for running the bots checker.

/// <summary>
/// Run the ActivatedBotsChecker routine in a separate thread
/// </summary>
public void StartBotsChecker()
{
    // This is sample code. In production you would want to apply 
    // more appropriate thread synchronization techniques
    backgroundThread = new Thread(new ThreadStart(ActivatedBotsChecker));
    backgroundThread.Start();
}

Initializing SIP Application API Application

Running a Lync Server 2010 SIP Application API managed application requires that the application first connect to the Lync Server 2010 computer. The connection involves creating a handle to the application itself, loading and compiling the application manifest, and creating a ServerAgent object that connects the application to the Lync Server 2010 computer. This process will not succeed unless the application is properly registered with the server. For information about how to deploy a Lync Server 2010 SIP Application API application, see Extending Unified Communications Services of UCMA Bots to PIC Clients: Building and Deploying Application (Part 5 of 5).) The following example shows how to connect a Lync Server 2010 SIP Application API managed application (app) with the specified application manifest, (amFile) to the Lync Server 2010 computer that hosts the application.

static ServerAgent ConnectToServer(object app, string amFile)
{
    try
    {
        ServerAgent.WaitForServerAvailable(3);      // 3 Attempts
    }
    catch (Exception e1)
    {
        Console.WriteLine("ERROR: Server unavailable - {0}", e1.Message);
        if (e1 is UnauthorizedException)
        {
            Console.WriteLine("must be running under an account that is a member of the \"RTC Server Applications\" local group");
        }
        return null;
    }


    ApplicationManifest am = ApplicationManifest.CreateFromFile(amFile);
    if (am == null)
    {
        Console.WriteLine("ERROR: {0} application manifest file not found.", amFile);
        return null;
    }

    try
    {
        am.Compile();
    }
    catch (CompilerErrorException e2)
    {
        Console.WriteLine("ERROR: {0} application manifest file contained errors:", amFile);
        foreach (string message in e2.ErrorMessages)
        {
            Console.WriteLine(message);
        }
        return null;
    }

    try
    {
        ServerAgent agent = new ServerAgent(app, am);
        return agent;
    }
    catch (Exception e3)
    {
        Console.WriteLine("ERROR: Unable to connect to server - {0}", e3.Message);
        return null;
    }
}

Processing Intercepted Messages in an Event Handling Loop

For the managed Lync Server application to process intercepted messages, a loop can be constructed after the AppEndpointManager class is instantiated and a ServerAgent object is obtained. The loop is needed for a reason. When the server calls the Dispatch function of the MSPL script that is embedded in the application manifest, it puts the intercepted message on the queue that is attached to by the application and signals the application in waiting. The application can then remove the event from the queue and process the message before going back to wait for the next event. The application can have the ServerAgent.ProcessEvent method invoked by the thread manager to remove the event from the queue and to process the message in the event handler. It can use the wait handle (WaitHandle) exposed on the ServerAgent class to go in waiting.

The following example shows how to set up the event pumping loop to receive and process intercepted message by the managed event handler.

static void Main(string[] args)
{
    Console.WriteLine("Starting PresenceSubInterceptorForBot...");

    try
    {
        appEndpointManager = new AppEndpointManager();
        PresenceSubInterceptorForBot app = new PresenceSubInterceptorForBot();
        ServerAgent agent = ConnectToServer(app, "PresenceSubInterceptorForBot.am");
        if (agent != null)
        {
            // Event dispatch loop.
            Console.WriteLine("App started.  Press Control-C to quit.");
            while (true)
            {
                agent.WaitHandle.WaitOne();
                ThreadPool.QueueUserWorkItem(new WaitCallback(agent.ProcessEvent));
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

The event-handling loop is interrupted by the user when the combined Control+C keys are pressed.

Additional Resources

For more information, see the following resources:

About the Author

Kurt De Ding is a Senior Programming Writer in the Microsoft Office Content Publishing (UA) group. Ajay Soni is a Senior Program Manager with Engineering, Community & Online (ECO) of Microsoft Services.