This class is used to perform the discovery process between the shared test case part and the pure WOPI test cases part.
Inheritance: HelperBase
Ejemplo n.º 1
0
        /// <summary>
        /// A method is used to perform the WOPI discovery process for the WOPI server.
        /// </summary>
        /// <param name="hostNameOfDiscoveryListener">A parameter represents the machine name which is hosting the discovery listener feature. It should be the test client name which is running the test suite.</param>
        /// <param name="sutControllerInstance">A parameter represents the IMS_WOPISUTControlAdapter instance which is used to make the WOPI server perform sending discovery request to the discovery listener.</param>
        public static void PerformDiscoveryProcess(string hostNameOfDiscoveryListener, IMS_WOPISUTControlAdapter sutControllerInstance)
        {
            if (HasPerformDiscoveryProcessSucceed)
            {
                return;
            }

            if (null == sutControllerInstance)
            {
                throw new ArgumentNullException("sutControllerInstance");
            }

            if (string.IsNullOrEmpty(hostNameOfDiscoveryListener))
            {
                throw new ArgumentNullException("hostNameOfDiscoveryListener");
            }

            // Call the "TriggerWOPIDiscovery" method of IMS_WOPISUTControlAdapter interface
            bool isDiscoverySuccessful = sutControllerInstance.TriggerWOPIDiscovery(hostNameOfDiscoveryListener);

            if (!isDiscoverySuccessful)
            {
                throw new InvalidOperationException("Could not perform the discovery process successfully.");
            }

            lock (lockObjectOfVisitDiscoveryProcessStatus)
            {
                hasPerformDiscoveryProcessSucceed = true;
            }

            DiscoveryProcessHelper.AppendLogs(typeof(DiscoveryProcessHelper), DateTime.Now, "Perform the trigger WOPI discovery process successfully.");
        }
Ejemplo n.º 2
0
        /// <summary>
        /// A method is used to clean the WOPI discovery process for the WOPI server.
        /// </summary>
        /// <param name="currentTestClient">A parameter represents the test client name which is running the test suite. This test client act as WOPI client and response discovery request from the WOPI server successfully.</param>
        /// <param name="sutControllerAdapterInstance">A parameter represents the IMS_WOPISUTControlAdapter instance which is used to make the WOPI server perform sending discovery request to the discovery listener.</param>
        public static void CleanUpDiscoveryProcess(string currentTestClient, IMS_WOPISUTControlAdapter sutControllerAdapterInstance)
        {
            // If the current SUT does not support MS-WOPI, the test suite will not perform any discovery process logics.
            if (!isCurrentSUTSupportWOPI)
            {
                return;
            }

            // If the test class invoke this, means the test class will uses the binding.
            long currentCleanUpStatusCounter = System.Threading.Interlocked.Decrement(ref cleanUpDiscoveryStatusCounter);

            if (currentCleanUpStatusCounter > 0)
            {
                return;
            }
            else if (0 == currentCleanUpStatusCounter)
            {
                // Clean up the WOPI discovery process record from so the WOPI server. The test suite act as WOPI client.
                if (DiscoveryProcessHelper.NeedToCleanUpDiscoveryRecord)
                {
                    DiscoveryProcessHelper.CleanUpDiscoveryRecord(currentTestClient, sutControllerAdapterInstance);
                }

                // Dispose the discovery request listener.
                DiscoveryProcessHelper.DisposeDiscoveryListener();
            }
            else
            {
                throw new InvalidOperationException(string.Format("The discovery clean up counter should not be less than zero. current value[{0}]", currentCleanUpStatusCounter));
            }
        }
        /// <summary>
        /// A method is used to restart the HTTP listener. It will dispose the original HTTP listener and then re-generate a HTTP listen instance to listen request.
        /// </summary>
        protected void RestartListener()
        {
            lock (threadLockObjectForAppendLog)
            {
                DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, "Try to restart the Httplistener.");
            }

            // If it is not in "stop" status, try to restart the Httplistener.
            if (ListenInstance.IsListening)
            {
                ListenInstance.Stop();
            }

            while (ListenInstance.IsListening)
            {
                // sleep zero, so that other thread can get the CPU timespan in a valid
                Thread.Sleep(0);
            }

            // Release the original HttpListener resource.
            ListenInstance.Abort();
            ((IDisposable)ListenInstance).Dispose();
            ListenInstance = null;

            // Restart a new HttpListener instance.
            ListenInstance = new HttpListener();
            this.SetPrefixForListener(ListenInstance);
        }
        /// <summary>
        /// A method is used to set the prefix for listener.
        /// </summary>
        /// <param name="listenerInstance">A parameter represents the HttpListener instance which will be set the listened prefix.</param>
        protected void SetPrefixForListener(HttpListener listenerInstance)
        {
            if (null == listenerInstance)
            {
                throw new ArgumentNullException("listenerInstance");
            }

            if (listenerInstance.IsListening)
            {
                throw new InvalidOperationException("The listener has been started, could not set listened prefix for it when it is in started status.");
            }

            // The discovery request must send to "http://{0}/hosting/discovery" URL, and the listener's prefix should append the "/" after the url.
            string listenedprefix = string.Format(@"http://{0}/hosting/discovery/", this.HostNameOfDiscoveryService);
            Uri    uri            = new Uri(listenedprefix);

            listenedprefix = uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
            ListenInstance.Prefixes.Add(listenedprefix + "/");
            ListenInstance.Start();

            lock (threadLockObjectForAppendLog)
            {
                DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Start the HttpListener [{0}] succeed.", Thread.CurrentThread.ManagedThreadId));
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// A method is used to check whether the WOPI server Cobalt feature, this feature depends on that the WOPI server whether implements MS-FSSHTTP. If current WOPI server does support Cobalt feature, this method will capture related requirement R961, otherwise this method will raise an inconclusive assertion.
 /// </summary>
 /// <param name="siteInstance">A parameter represents the site instance.</param>
 public static void PerformSupportCobaltCheck(ITestSite siteInstance)
 {
     DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <ITestSite>(siteInstance, "siteInstance", "PerformSupportCobaltCheck");
     if (!Common.IsRequirementEnabled("MS-WOPI", 961, siteInstance))
     {
         siteInstance.Assert.Inconclusive(@"The WOPI server does not support the Cobalt feature. To supporting this feature, the WOPI server must implement the MS-FSSHTTP protocol.It is determined by ""R961Enabled_MS-WOPI"" SHOULDMAY property.");
     }
 }
Ejemplo n.º 6
0
        /// <summary>
        /// A method is used to get a xml string from a WOPI Discovery type object. The xml string is used to response the discovery request.
        /// </summary>
        /// <param name="discoveryObject">A parameter represents the WOPI Discovery object which contain the discovery information.</param>
        /// <returns>A parameter represents the xml string which contains the discovery information.</returns>
        public static string GetDiscoveryXmlFromDiscoveryObject(wopidiscovery discoveryObject)
        {
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <wopidiscovery>(discoveryObject, "discoveryObject", "GetDiscoveryXmlFromDiscoveryObject");

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(wopidiscovery));
            string        xmlString     = string.Empty;

            MemoryStream memorySteam = null;

            try
            {
                memorySteam = new MemoryStream();
                StreamWriter streamWriter = null;
                try
                {
                    streamWriter = new StreamWriter(memorySteam, Encoding.UTF8);

                    // Remove w3c default namespace prefix in serialize process.
                    XmlSerializerNamespaces nameSpaceInstance = new XmlSerializerNamespaces();
                    nameSpaceInstance.Add(string.Empty, string.Empty);
                    xmlSerializer.Serialize(streamWriter, discoveryObject, nameSpaceInstance);

                    // Read the MemoryStream to output the xml string.
                    memorySteam.Position = 0;
                    using (StreamReader streamReader = new StreamReader(memorySteam))
                    {
                        xmlString = streamReader.ReadToEnd();
                    }
                }
                finally
                {
                    if (streamWriter != null)
                    {
                        streamWriter.Dispose();
                    }
                }
            }
            finally
            {
                if (memorySteam != null)
                {
                    memorySteam.Dispose();
                }
            }

            if (string.IsNullOrEmpty(xmlString))
            {
                throw new InvalidOperationException("Could not get the xml string.");
            }

            // Format the serialized xml string.
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.LoadXml(xmlString);
            return(xmlDoc.OuterXml);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// A method used to read bytes data from the stream of the HTTP response.
        /// </summary>
        /// <param name="bodyBinaries">A parameter represents the stream which contain the body binaries data.</param>
        /// <param name="contentLengthValue">A parameter represents the length of the body binaries.</param>
        /// <returns>A return value represents the raw body content. If the body length is larger than (int.MaxValue) bytes, the body contents will be chunked by 1024 bytes. The max length of this method is (1024 * int.MaxValue) bytes.</returns>
        private static List <byte[]> ReadBytesFromHttpBodyStream(Stream bodyBinaries, long contentLengthValue)
        {
            if (null == bodyBinaries)
            {
                throw new ArgumentNullException("bodyBinaries");
            }

            long maxKBSize = (long)int.MaxValue;
            long totalSize = contentLengthValue;

            if (contentLengthValue > maxKBSize * 1024)
            {
                throw new InvalidOperationException(string.Format("The test suite only support [{0}]KB size content in a HTTP response.", maxKBSize));
            }

            List <byte[]> bytesOfResponseBody = new List <byte[]>();
            bool          isuseChunk          = false;

            using (BinaryReader binReader = new BinaryReader(bodyBinaries))
            {
                if (contentLengthValue < int.MaxValue && contentLengthValue > 0)
                {
                    byte[] bytesBlob = binReader.ReadBytes((int)contentLengthValue);
                    bytesOfResponseBody.Add(bytesBlob);
                }
                else
                {
                    isuseChunk = true;
                    totalSize  = 0;

                    // set chunk size to 1KB per reading.
                    int    chunkSize      = 1024;
                    byte[] bytesBlockTemp = null;

                    do
                    {
                        bytesBlockTemp = binReader.ReadBytes(chunkSize);
                        if (bytesBlockTemp.Length > 0)
                        {
                            bytesOfResponseBody.Add(bytesBlockTemp);
                            totalSize += bytesBlockTemp.Length;
                        }
                    }while (bytesBlockTemp.Length > 0);
                }
            }

            string chunkProcessLogs = string.Format(
                "Read [{0}] KB size data from response body.{1}",
                (totalSize / 1024.0).ToString("f2"),
                isuseChunk ? "Use the chunk reading mode." : string.Empty);

            DiscoveryProcessHelper.AppendLogs(typeof(WOPIResponseHelper), chunkProcessLogs);

            return(bytesOfResponseBody);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// A method is used to start listening the discovery request from the WOPI server. If the listen thread has existed, the DiscoverProcessHelper will not start any new listen thread.
        /// </summary>
        /// <param name="currentTestClient">A parameter represent the current test client which acts as WOPI client to listen the discovery request.</param>
        /// <param name="progId">A parameter represents the id of program which is associated with folder level visit in discovery process. This value must be valid for WOPI server. For Microsoft products, this value can be "OneNote.Notebook". It is used to ensure the WOPI server can support folder level visit ability in WOPI mode when receive the value from the discovery response.</param>
        public static void StartDiscoveryListen(string currentTestClient, string progId)
        {
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <string>(currentTestClient, "currentTestClient", "StartDiscoveryListen");
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <string>(progId, "progId", "StartDiscoveryListen");

            if (null == discoveryListenerInstance)
            {
                string discoveryXmlResponse = GetDiscoveryResponseXmlString(currentTestClient, progId);
                discoveryListenerInstance = new DiscoveryRequestListener(currentTestClient, discoveryXmlResponse);
                discoveryListenerInstance.StartListen();
            }
        }
        /// <summary>
        /// A method is used to stop listen process. This method will abort the thread which is listening discovery request and release all resource are used by the thread.
        /// </summary>
        public void StopListen()
        {
            lock (threadLockStaticObjectForVisitThread)
            {
                // If the listen thread has not been start, skip the stop operation.
                if (!hasStartListenThread)
                {
                    return;
                }

                this.IsRequiredStop = true;

                lock (threadLockObjectForAppendLog)
                {
                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Stop the listening thread.The listening thread managed Id[{0}]", listenThreadHandle.ManagedThreadId));
                }

                if (listenThreadHandle != null && listenThreadHandle.ThreadState != ThreadState.Unstarted &&
                    ListenInstance != null)
                {
                    lock (threadLockObjectForAppendLog)
                    {
                        // Close the http listener and release the resource used by listener. This might cause the thread generate exception and then the thread will be expected to end and join to the main thread.
                        ListenInstance.Abort();
                        ((IDisposable)ListenInstance).Dispose();
                        DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Release the Httplistener resource. The listening thread managed Id[{0}]", listenThreadHandle.ManagedThreadId));
                    }

                    // Wait the thread join to the main caller thread.
                    TimeSpan listenThreadJoinTimeOut = new TimeSpan(0, 0, 1);
                    bool     isthreadEnd             = listenThreadHandle.Join(listenThreadJoinTimeOut);

                    // If the thread could not end as expected, abort this thread.
                    if (!isthreadEnd)
                    {
                        if ((listenThreadHandle.ThreadState & (ThreadState.Stopped | ThreadState.Unstarted)) == 0)
                        {
                            listenThreadHandle.Abort();
                            lock (threadLockObjectForAppendLog)
                            {
                                DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Abort the listening thread. The listening thread managed Id[{0}]", listenThreadHandle.ManagedThreadId));
                            }
                        }
                    }

                    // Set the static status to tell other instance, the listen thread has been abort.
                    hasStartListenThread = false;
                    listenThreadHandle   = null;
                }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// A method is used to get raw body contents whose length is in 1 to int.MaxValue bytes scope.
        /// </summary>
        /// <param name="wopiHttpResponse">A parameter represents the HTTP response.</param>
        /// <returns>A return value represents the raw body content.</returns>
        public static byte[] GetContentFromResponse(WOPIHttpResponse wopiHttpResponse)
        {
            List <byte[]> rawBytesOfBody = ReadRawHTTPResponseToBytes(wopiHttpResponse);

            byte[] returnContent = rawBytesOfBody.SelectMany(bytes => bytes).ToArray();

            DiscoveryProcessHelper.AppendLogs(
                typeof(WOPIResponseHelper),
                string.Format(
                    "Read normal size(1 to int.MaxValue bytes) data from response. actual size[{0}] bytes",
                    returnContent.Length));

            return(returnContent);
        }
        /// <summary>
        /// A method is used to start the listen thread to listen the discovery request.
        /// </summary>
        /// <returns>A return value represents the thread instance handle, which is processing the listen logic. This thread instance can be used to control the thread's status and clean up.</returns>
        public Thread StartListen()
        {
            // Verify whether the listen thread has been started from a DiscoveryRequestListener type instance.
            lock (threadLockStaticObjectForVisitThread)
            {
                lock (threadLockObjectForAppendLog)
                {
                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, @"Try to start listener thread from current thread.");
                }

                if (null == ListenInstance)
                {
                    ListenInstance = new HttpListener();
                }

                if (hasStartListenThread)
                {
                    lock (threadLockObjectForAppendLog)
                    {
                        DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format(@"The listen thread [{0}] exists.", listenThreadHandle.ManagedThreadId));
                    }

                    return(listenThreadHandle);
                }

                if (!ListenInstance.IsListening)
                {
                    this.SetPrefixForListener(ListenInstance);
                }

                while (!ListenInstance.IsListening)
                {
                    // Sleep 1 second to wait until the status is stable, and allow other threads get the control to update the status.
                    Thread.Sleep(1000);
                }

                listenThreadHandle      = new Thread(this.ListenToRequest);
                listenThreadHandle.Name = "Listen Discovery request thread";
                listenThreadHandle.Start();

                lock (threadLockObjectForAppendLog)
                {
                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Start the listening thread. The listening thread managed Id[{0}]", listenThreadHandle.ManagedThreadId));
                }

                // Set the status to indicate there has started a listen thread.
                hasStartListenThread = true;
                return(listenThreadHandle);
            }
        }
        /// <summary>
        /// A method is used to restart the HTTP listener. It will dispose the original HTTP listener and then re-generate a HTTP listen instance to listen request.
        /// </summary>
        protected void RestartListener()
        {
            lock (threadLockObjectForAppendLog)
            {
                DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, "Try to restart the Httplistener.");
            }
            // Release the original HttpListener resource.
            ListenInstance.Stop();
            ListenInstance = null;

            // Restart a new TcpListener instance.
            IPAddress  iPAddress = IPAddress.Any;
            IPEndPoint endPoint  = new IPEndPoint(iPAddress, 80);

            ListenInstance = new TcpListener(endPoint);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// This method is used to convert the XML date to the Discovery object.
        /// </summary>
        /// <param name="xmlValue">The value of the xml string.</param>
        /// <returns>The object value which is converted from the xml string.</returns>
        public static wopidiscovery DeserializeXmlToDiscoveryObject(string xmlValue)
        {
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <string>(xmlValue, "xmlString", "DeserializeXmlToDiscoveryObject");

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(wopidiscovery));
            wopidiscovery discovery     = null;

            using (StringReader strReader = new StringReader(xmlValue))
            {
                discovery = xmlSerializer.Deserialize(strReader) as wopidiscovery;
                if (null == discovery)
                {
                    throw new ArgumentNullException("discovery", "Could not get the current xml string to the expected Discovery type.");
                }
            }

            return(discovery);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// A method is used to perform the discovery process
        /// </summary>
        /// <param name="currentTestClient">A parameter represents the current test client which is listening the discovery request.</param>
        /// <param name="sutControllerAdapterInstance">A parameter represents the IMS_WOPISUTControlAdapter instance which is used to make the WOPI server perform sending discovery request to the discovery listener.</param>
        /// <param name="siteInstance">A parameter represents the ITestSite instance which is used to get the test context.</param>
        public static void PerformDiscoveryProcess(string currentTestClient, IMS_WOPISUTControlAdapter sutControllerAdapterInstance, ITestSite siteInstance)
        {
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <string>(currentTestClient, "currentTestClient", "PerformDiscoveryProcess");
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <IMS_WOPISUTControlAdapter>(sutControllerAdapterInstance, "sutControllerAdapterInstance", "PerformDiscoveryProcess");
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <ITestSite>(siteInstance, "siteInstance", "PerformDiscoveryProcess");

            // If the test class invoke this, means the test class will uses the WOPI discovery binding. The test suite will count all WOPI discovery usage of test classes
            System.Threading.Interlocked.Increment(ref cleanUpDiscoveryStatusCounter);

            // Start the listener, if the listen thread has been start, the DiscoverProcessHelper will not start any new listen thread.
            DiscoveryProcessHelper.StartDiscoveryListen(currentTestClient, progId);

            // Initialize the WOPI Discovery process so that the WOPI server will use the test suite as WOPI client.
            if (!DiscoveryProcessHelper.HasPerformDiscoveryProcessSucceed)
            {
                DiscoveryProcessHelper.PerformDiscoveryProcess(currentTestClient, sutControllerAdapterInstance);
            }
        }
        /// <summary>
        /// A method is used to start the listen thread to listen the discovery request.
        /// </summary>
        /// <returns>A return value represents the thread instance handle, which is processing the listen logic. This thread instance can be used to control the thread's status and clean up.</returns>
        public Thread StartListen()
        {
            // Verify whether the listen thread has been started from a DiscoveryRequestListener type instance.
            lock (threadLockStaticObjectForVisitThread)
            {
                lock (threadLockObjectForAppendLog)
                {
                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, @"Try to start listener thread from current thread.");
                }

                if (null == ListenInstance)
                {
                    IPAddress  iPAddress = IPAddress.Any;
                    IPEndPoint endPoint  = new IPEndPoint(iPAddress, 80);
                    ListenInstance = new TcpListener(endPoint);
                }

                if (hasStartListenThread)
                {
                    lock (threadLockObjectForAppendLog)
                    {
                        DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format(@"The listen thread [{0}] exists.", listenThreadHandle.ManagedThreadId));
                    }

                    return(listenThreadHandle);
                }

                listenThreadHandle      = new Thread(this.ListenToRequest);
                listenThreadHandle.Name = "Listen Discovery request thread";
                listenThreadHandle.Start();

                lock (threadLockObjectForAppendLog)
                {
                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Start the listening thread. The listening thread managed Id[{0}]", listenThreadHandle.ManagedThreadId));
                }

                // Set the status to indicate there has started a listen thread.
                hasStartListenThread = true;
                return(listenThreadHandle);
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// A method is used to generate response of a WOPI discovery request. It indicates the WOPI client supports 3 types file extensions: ".txt", ".zip", ".one"
        /// </summary>
        /// <param name="currentTestClientName">A parameter represents the current test client name which is used to construct WOPI client's app name in WOPI discovery response.</param>
        /// <param name="progId">A parameter represents the id of program which is associated with folder level visit in discovery process. This value must be valid for WOPI server.</param>
        /// <returns>A return value represents the response of a WOPI discovery request.</returns>
        public static string GetDiscoveryResponseXmlString(string currentTestClientName, string progId)
        {
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <string>(currentTestClientName, "currentTestClientName", "GetDiscoveryResponseXmlString");
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <string>(progId, "progId", "GetDiscoveryResponseXmlString");

            wopidiscovery wopiDiscoveryInstance = new wopidiscovery();

            // Pass the prog id, so that the WOPI discovery response logic will use the prog id value.
            progIdValue = progId;

            // Add http and https net zone into the wopiDiscovery
            wopiDiscoveryInstance.netzone = GetNetZonesForWopiDiscoveryResponse(currentTestClientName);

            // ProofKey element
            wopiDiscoveryInstance.proofkey          = new ct_proofkey();
            wopiDiscoveryInstance.proofkey.oldvalue = RSACryptoContext.PublicKeyStringOfOld;
            wopiDiscoveryInstance.proofkey.value    = RSACryptoContext.PublicKeyStringOfCurrent;
            string xmlStringOfResponseDiscovery = WOPISerializerHelper.GetDiscoveryXmlFromDiscoveryObject(wopiDiscoveryInstance);

            return(xmlStringOfResponseDiscovery);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// A method is used to clean up the WOPI discovery record for the WOPI server. For removing the record successfully, the WOPI server can be triggered the WOPI discovery process again.
        /// </summary>
        /// <param name="wopiClientName">A parameter represents the WOPI client name which should have been discovered by WOPI server</param>
        /// <param name="sutControllerInstance">A parameter represents the IMS_WOPISUTControlAdapter instance which is used to make the WOPI server clean up discovery record for the specified WOPI client.</param>
        public static void CleanUpDiscoveryRecord(string wopiClientName, IMS_WOPISUTControlAdapter sutControllerInstance)
        {
            DiscoveryProcessHelper.CheckInputParameterNullOrEmpty <IMS_WOPISUTControlAdapter>(sutControllerInstance, "sutControllerInstance", "CleanUpDiscoveryRecord");

            if (!NeedToCleanUpDiscoveryRecord)
            {
                return;
            }

            lock (lockObjectOfVisitDiscoveryProcessStatus)
            {
                if (hasPerformDiscoveryProcessSucceed && !hasPerformCleanUpForDiscovery)
                {
                    bool isDiscoveryRecordRemoveSuccessful = sutControllerInstance.RemoveWOPIDiscoveryRecord(wopiClientName);
                    if (!isDiscoveryRecordRemoveSuccessful)
                    {
                        throw new InvalidOperationException("Could not remove the discovery record successfully, need to remove that manually.");
                    }

                    hasPerformCleanUpForDiscovery = true;
                }
            }
        }
        /// <summary>
        /// A method is used to listening the discovery request. It will be executed by a thread which is started on ListenThreadInstance method.
        /// </summary>
        protected void ListenToRequest()
        {
            ListenInstance.Start();

            // If the listener is listening, just keep on execute below code.
            while (hasStartListenThread)
            {
                try
                {
                    TcpClient client = ListenInstance.AcceptTcpClient();
                    if (client.Connected == true)
                    {
                        Console.WriteLine("Created connection");
                    }
                    // if the calling thread requires stopping the listening mission, just return and exit the loop. This value of "IsrequireStop" property is managed by "StopListen" method.
                    if (this.IsRequiredStop)
                    {
                        break;
                    }

                    lock (threadLockStaticObjectForVisitThread)
                    {
                        // Double check the "IsrequireStop" status.
                        if (this.IsRequiredStop)
                        {
                            break;
                        }
                    }

                    lock (threadLockObjectForAppendLog)
                    {
                        string logMsg = string.Format("Listening............ The listen thread: managed id[{0}].", Thread.CurrentThread.ManagedThreadId);
                        DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, logMsg);
                    }
                    NetworkStream netstream = client.GetStream();
                    try
                    {
                        byte[] buffer = new byte[2048];

                        int    receivelength = netstream.Read(buffer, 0, 2048);
                        string requeststring = Encoding.UTF8.GetString(buffer, 0, receivelength);

                        if (!requeststring.StartsWith(@"GET /hosting/discovery", StringComparison.OrdinalIgnoreCase))
                        {
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        lock (threadLockObjectForAppendLog)
                        {
                            DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("The listen thread catches an [{0}] exception:[{1}].", ex.GetType().Name, ex.Message));
                        }

                        lock (threadLockStaticObjectForVisitThread)
                        {
                            if (this.IsRequiredStop)
                            {
                                lock (threadLockObjectForAppendLog)
                                {
                                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, "Requires stopping the Httplistener.");
                                }

                                return;
                            }
                            else
                            {
                                this.RestartListener();
                            }
                        }
                    }
                    bool writeResponseSucceed = false;
                    try
                    {
                        string statusLine = "HTTP/1.1 200 OK\r\n";
                        byte[] responseStatusLineBytes = Encoding.UTF8.GetBytes(statusLine);
                        string responseHeader          =
                            string.Format(
                                "Content-Type: text/xml; charset=UTf-8\r\nContent-Length: {0}\r\n", this.ResponseDiscovery.Length);
                        byte[] responseHeaderBytes = Encoding.UTF8.GetBytes(responseHeader);
                        byte[] responseBodyBytes   = Encoding.UTF8.GetBytes(this.ResponseDiscovery);
                        writeResponseSucceed = true;
                        netstream.Write(responseStatusLineBytes, 0, responseStatusLineBytes.Length);
                        netstream.Write(responseHeaderBytes, 0, responseHeaderBytes.Length);
                        netstream.Write(new byte[] { 13, 10 }, 0, 2);
                        netstream.Write(responseBodyBytes, 0, responseBodyBytes.Length);
                        client.Close();
                    }
                    catch (Exception ex)
                    {
                        lock (threadLockObjectForAppendLog)
                        {
                            DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("The listen thread catches an [{0}] exception:[{1}] on responding.", ex.GetType().Name, ex.Message));
                        }

                        lock (threadLockStaticObjectForVisitThread)
                        {
                            if (this.IsRequiredStop)
                            {
                                lock (threadLockObjectForAppendLog)
                                {
                                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Catch an exception:[{0}]. Current requires stopping the Httplistener. Thread managed Id[{1}].", ex.Message, Thread.CurrentThread.ManagedThreadId));
                                }

                                return;
                            }
                            else
                            {
                                this.RestartListener();
                            }
                        }
                    }

                    if (writeResponseSucceed)
                    {
                        lock (threadLockStaticObjectForVisitThread)
                        {
                            // Setting the status.
                            if (!hasResponseDiscoveryRequestSucceed)
                            {
                                hasResponseDiscoveryRequestSucceed = true;
                            }
                        }

                        lock (threadLockObjectForAppendLog)
                        {
                            DiscoveryProcessHelper.AppendLogs(
                                currentHelperType,
                                DateTime.Now,
                                string.Format(
                                    "Response the discovery requestsucceed! The listen thread managedId[{0}]",
                                    Thread.CurrentThread.ManagedThreadId));
                        }
                    }
                }
                catch (SocketException ee)
                {
                    DiscoveryProcessHelper.AppendLogs(
                        currentHelperType,
                        DateTime.Now,
                        string.Format("SocketException: {0}", ee.Message));
                }
            }
        }
        /// <summary>
        /// A method is used to listening the discovery request. It will be executed by a thread which is started on ListenThreadInstance method.
        /// </summary>
        protected void ListenToRequest()
        {
            // If the listener is listening, just keep on execute below code.
            while (ListenInstance.IsListening)
            {
                // if the calling thread requires stopping the listening mission, just return and exit the loop. This value of "IsrequireStop" property is managed by "StopListen" method.
                if (this.IsRequiredStop)
                {
                    break;
                }

                lock (threadLockStaticObjectForVisitThread)
                {
                    // Double check the "IsrequireStop" status.
                    if (this.IsRequiredStop)
                    {
                        break;
                    }
                }

                lock (threadLockObjectForAppendLog)
                {
                    string logMsg = string.Format("Listening............ The listen thread: managed id[{0}].", Thread.CurrentThread.ManagedThreadId);
                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, logMsg);
                }

                // Get an incoming request.
                HttpListenerContext  listenContext            = null;
                HttpListenerResponse responseOfCurrentRequest = null;
                HttpListenerRequest  currentRequest           = null;

                try
                {
                    listenContext            = ListenInstance.GetContext();
                    currentRequest           = listenContext.Request as HttpListenerRequest;
                    responseOfCurrentRequest = listenContext.Response as HttpListenerResponse;

                    if (!currentRequest.RawUrl.Equals(@"/hosting/discovery", StringComparison.OrdinalIgnoreCase))
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    lock (threadLockObjectForAppendLog)
                    {
                        DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("The listen thread catches an [{0}] exception:[{1}].", ex.GetType().Name, ex.Message));
                    }

                    lock (threadLockStaticObjectForVisitThread)
                    {
                        if (this.IsRequiredStop)
                        {
                            lock (threadLockObjectForAppendLog)
                            {
                                DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, "Requires stopping the Httplistener.");
                            }

                            return;
                        }
                        else
                        {
                            this.RestartListener();
                        }
                    }
                }

                if (responseOfCurrentRequest != null)
                {
                    responseOfCurrentRequest.ContentType     = "text/xml";
                    responseOfCurrentRequest.ContentEncoding = Encoding.UTF8;
                    responseOfCurrentRequest.StatusCode      = 200;

                    // Get the xml response.
                    XmlDocument reponseXml = new XmlDocument();
                    reponseXml.LoadXml(this.ResponseDiscovery);
                    bool writeResponseSucceed = false;
                    try
                    {
                        using (XmlTextWriter xmlWriter = new XmlTextWriter(responseOfCurrentRequest.OutputStream, Encoding.UTF8))
                        {
                            reponseXml.Save(xmlWriter);
                            writeResponseSucceed = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        lock (threadLockObjectForAppendLog)
                        {
                            DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("The listen thread catches an [{0}] exception:[{1}] on responding.", ex.GetType().Name, ex.Message));
                        }

                        lock (threadLockStaticObjectForVisitThread)
                        {
                            if (this.IsRequiredStop)
                            {
                                lock (threadLockObjectForAppendLog)
                                {
                                    DiscoveryProcessHelper.AppendLogs(currentHelperType, DateTime.Now, string.Format("Catch an exception:[{0}]. Current requires stopping the Httplistener. Thread managed Id[{1}].", ex.Message, Thread.CurrentThread.ManagedThreadId));
                                }

                                return;
                            }
                            else
                            {
                                this.RestartListener();
                            }
                        }
                    }

                    if (writeResponseSucceed)
                    {
                        lock (threadLockStaticObjectForVisitThread)
                        {
                            // Setting the status.
                            if (!hasResponseDiscoveryRequestSucceed)
                            {
                                hasResponseDiscoveryRequestSucceed = true;
                            }
                        }

                        lock (threadLockObjectForAppendLog)
                        {
                            DiscoveryProcessHelper.AppendLogs(
                                currentHelperType,
                                DateTime.Now,
                                string.Format(
                                    "Response the discovery request from [{0}] succeed! The listen thread managedId[{1}]",
                                    currentRequest.UserHostName,
                                    Thread.CurrentThread.ManagedThreadId));
                        }
                    }
                }
            }
        }