In this post, I’m going to demonstrate how to add automatic reconnection logic to UCMA applications, which is otherwise not well documented.
In an ideal world, one’s custom OCS 2007 R2 middle-tier applications never lose their connections to OCS front-end servers. In the real world, however, unplanned network and server outages will disrupt these connections. If you do not want to be responsible for manually restarting your UCMA 2.0 applications each time this happens, you need to add automatic reconnection logic to these applications.
How to do this is not fully documented. And, as far as I know, there are no sample applications showing how to
1) Detect that you have lost the connection to the front-end server, and
2) Re-establish the connection to the front end server.
So, I shall provide some code samples in this blog that help clarify how to accomplish these two important tasks.
In order to understand the solution, you need to understand how UCMA signals an application connection, disconnection and failure. In particular, these three points are key:
1) The connection to the OCS front-end server is created when you establish the application endpoint via the LocalEndpoint.EndEstablish() method. Any failure establishing the connection will be thrown by this method.
2) When the local endpoint is disconnected from the OCS front-end server, its state will transition to Terminating and then Terminated.
3) An attempt to establish a call using a disconnected endpoint via the Call.EndEstablish() method will throw a InvalidOperationException exception.
Here are the code samples that you can add to your UCMA 2.0 application to detect a lost connection and re-establish it.
Step 1: Detect that the application has lost its connection to the OCS front-end server
1.1) Register your local endpoint for state changes:
LocalEndpoint _endpoint;
….
_endpoint.StateChanged += new EventHandler<LocalEndpointStateChangedEventArgs>(_endpoint_StateChanged);
1.2) Implement the _endpoint_StateChanged event handler:
/// <summary>
/// Will be true if we need to re-establish the endpoint's connection to the front end server.
/// </summary>
bool needReConnect;
/// <summary>
/// Called when endpoint state changes.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void _endpoint_StateChanged(object sender, LocalEndpointStateChangedEventArgs args)
{
try
{
if (args.State == LocalEndpointState.Terminated)
{
Console.WriteLine("endpoint state is now terminated.");
// Endpoint lost connection to OCS server. Need to re-establish our endpoint.
needReConnect = true;
}
else if (args.State == LocalEndpointState.Reestablishing)
{
Console.WriteLine("endpoint state is re-establishing.");
}
else if (args.State == LocalEndpointState.Established)
{
Console.WriteLine("endpoint state is now established.");
needReConnect = false;
}
}
catch (Exception e)
{
HandleException(e);
}
}
Step 2: Re-establish the connection with the front-end server
2.1) Before making your next call to the OCS server, add the following code:
…
// Do we need to re-establish our connection with the OCS front end server?
if (needReConnect)
{
needReConnect = (ReestablishEndpoint() ? false : true);
}
if (false == needReConnect)
{
// Continue on with call, etc.
}
// Otherwise, try again the next time around
…
2.2) Implement the ReestablishEndpoint() method.
/// <summary>
/// Returns true if get reconnected, false otherwise
/// </summary>
/// <returns>bool</returns>
private static bool ReestablishEndpoint()
{
bool success = false;
try
{
// Terminate the endpoint.
// Terminate the platform.
ShutdownPlatform();
// Re-initialize the platform and endpoint
InitPlatform();
success = true;
}
catch (Exception e)
{
Console.WriteLine("Re-establish failed.");
HandleException(e);
}
return success;
}
2.3) Implement the ShutdownPlatform() method.
CollaborationPlatform _collabPlatform;
/// <summary>
/// Uninitialize the UCMA platform.
/// </summary>
private static void ShutdownPlatform()
{
…
// Terminate the endpoint.
if (_endpoint != null)
{
…
_endpoint.StateChanged -= _endpoint_StateChanged;
_endpoint.EndTerminate(_endpoint.BeginTerminate(null, null));
_endpoint = null;
}
if (_collabPlatform != null)
{
_collabPlatform.EndShutdown(_collabPlatform.BeginShutdown(null, null));
_collabPlatform = null;
}
}
2.4) Implement the InitPlatform() method.
/// <summary>
/// Initializes the UCMA platform and endpoint.
/// </summary>
private static void InitPlatform()
{
…
_collabPlatform = new CollaborationPlatform(platformSettings);
Console.Write("Starting CollaborationPlatform... ");
_collabPlatform.EndStartup(_collabPlatform.BeginStartup(null, null));
Console.WriteLine("Complete");
…
_endpoint = new UserEndpoint(_collabPlatform, settings); // or ApplicationEndpoint, as appropriate
Console.Write("Establishing Endpoint... ");
_endpoint.EndEstablish(_endpoint.BeginEstablish(null, _endpoint));
Console.WriteLine("Complete");
// Register for state changes
_endpoint.StateChanged += new EventHandler<LocalEndpointStateChangedEventArgs>(_endpoint_StateChanged);
…
}
Note that the local endpoint state must be Idle when BeginEstablish() is called.
For this reason, this sample terminate both the local endpoint and the collaboration platform before trying to re-establish the endpoint’s connection with the OCS front-end server.
Finally, it’s worth noting that you can catch the InvalidOperationException exception when attempting to establish a new call with the local endpoint. This allows you to log a message with more complete context than the one that the collaboration platform provides:
Call call;
…
call.EndEstablish(call.BeginEstablish(null, null));
catch (InvalidOperationException e)
{
// NOTE:
// If the endpoint has been disconnected from the front end server, then the error message text is
// "Endpoint is currently terminating or already terminated"
if (e.ToString().Contains("Endpoint is currently terminating or already terminated"))
{
// Just in case we do not get the state change event on the local endpoint…
// We need to re-establish a connection with the front end server.
needReConnect = true;
// TODO: Log a more informative error.
}
}
Note that we are currently using this code in several of our internal UCMA 2.0 applications and the applications are successfully reconnecting after OCS front end server re-starts.
That is it! Let me know if you find this useful! Have fun coding…