snowolf

          這樣的一種生活
          posts - 23, comments - 5, trackbacks - 0, articles - 11

          Live Communications Server Application API (1)

          Posted on 2006-01-17 09:43 snowolf 閱讀(436) 評論(0)  編輯  收藏 所屬分類: 其他

          Live Communications Server Application API
          發(fā)布時間:2005 年 6 月

           
          LCS API套件中包括:
          Microsoft SIP Processing Language(MSPL)、Microsoft.Rtc.Sip命名空間、application manifests 和為LCS構(gòu)建SIP應(yīng)用程序的資料。
          Note   The Live Communications Server Application API currently does not support SIP dialogs and UAC server behaviors. Future versions of the API will add support for these features.
          1. Application manifests
          The application manifest is an XML document that describes a Live Communications Server application to the server on which it is running. This document is presented to the server when the application registers with Live Communications Server through the Microsoft.Rtc.Sip.ServerAgent managed class.
          1.1 Application manifests構(gòu)成:
          Application manifests由以下三部分組成:
          1.1.1 <alias:applicationManifest>標(biāo)簽。
          在這個標(biāo)簽內(nèi)裝入應(yīng)用程序?qū)傩裕ˋpplication attributes)和消息過濾腳本(MSPL),可以為"alias"定義一個別名,微軟建議使用默認(rèn)別名"ls"。
          1.1.2 A set of application attributes that defines key properties of the application, such as the SIP message types to filter and whether it is script-only.
          1.1.3 用MSPL語言寫的消息過濾腳本。
          在CDATA element里被附加上<alias:splScript>標(biāo)簽。
          1.2 Application manifests部屬:
          這個Application manifests文件,一次建立后,可以和裝配件(assembly)里的resource一樣,植入應(yīng)用程序內(nèi)部,或者像一個外部文件一樣存在。
          1.2.1 植入assembly內(nèi)部:
          用Microsoft.Rtc.Sip命名空間的ApplicationManifest類,在新生成的 ApplicationManifest對象里用Compile方法對它進行編譯。樣里代碼如下:
                  ResourceManager myResourceManager = new ResourceManager(MyApplicationType);
                  
          string appManifestXml = myResourceManager.GetString("appManifest");
                  ApplicationManifest myAppManifest 
          = ApplicationManifest.CreateFromString(appManifestXml);
                  
          try {
                      myAppManifest.Compile();
                  }

                  
          catch (CompilerErrorException cee) {
                      Console.WriteLine(
          "Failed to compile.");
                      
          foreach (string message in cee.ErrorMessages) {
                          Console.WriteLine(message);
                      }

                      
          return
          ;
                  }

                         
                         編譯成功后,這個編譯過的Application manifests部屬到代理服務(wù)器上,
          1.2.2 外部文件格式:
          下面是一個僅有SIP INVITE and MESSAGE請求的基本的application manifest:
                         <?xml version="1.0" ?>
                         
          <
          lc:applicationManifest
                       
          appUri="http://www.adatum.com/myApplicationLocation"

                       xmlns:lc
          ="http://schemas.microsoft.com/lc/2003/05">

                            
          <lc:requestFilter methodNames="INVITE,MESSAGE"
           
                                        strictRoute
          ="false"
           
                                  registrarGenerated
          ="true"

                                  domainSupported
          ="true">

                            
          <lc:responseFilter reasonCodes="NONE" />

                            
          <lc:proxyByDefault action="true" />

                          
          <lc:scriptOnly />

                       
          <lc:splScript><![CDATA[

                                        if (sipRequest) {
                                      if (sipRequest.Method == StandardMethod.Invite) {
                                    Dispatch("NameOfInviteHandlerMethodInApplicationHere");
                                      }
                                           else if (sipRequest.Method == StandardMethod.Message) {
                                              Dispatch("NameofMessageHandlerMethodInApplicationHere");
                                      }
                                        }
                       
          ]]></lc:splScript>

                         
          </lc:applicationManifest>
          1.3 Application Attributes
          Application Attibutes在消息過濾腳本的前面,在<lc:applicationManifest>標(biāo)簽的后面,包含詳細(xì)的描述LCS應(yīng)用程序的數(shù)據(jù)。例如下面所示:
                         <?xml version="1.0" ?>
                         
          <
          lc:applicationManifest
                          
          lc:appUri="http://www.adatum.com/applicationName"

                          xmlns:lc
          =http://schemas.microsoft.com/lcs/2004/05>
                           
          application attributes
                         <lc:splScript
          ><![CDATA[

                           message filter script
                         
          ]]></lc:splScript>

          </lc:applicationManifest>

                 
                 其中,xmlns屬性指定了用那個版本的LCS來運行應(yīng)用程序,如果是LCS2003就采用下面的方式:
                 xmlns:lc=http://schemas.microsoft.com/rtc/2003/05
          共有下列應(yīng)用程序?qū)傩詷?biāo)簽可供Application manifests使用:
          1.3.1
           <lc:proxyByDefault  action="true|false" />

          說明:為應(yīng)用程序指定默認(rèn)代理行為。
          如果是true,服務(wù)器自動代理任意消息,應(yīng)用程序不依據(jù)句柄執(zhí)行。如果是false,消息被拋出,應(yīng)用程序結(jié)束,同時,一方將不會收到它。
          1.3.2
          <lc:scriptOnly />

          說明:當(dāng)部署時,指定應(yīng)用程序不含托管代碼的成分。
          1.3.3
          <lc:requestFilter methodNames="METHOD_NAMES|NONE|ALL" registrarGenerated="true|false"       strictRoute="true|false"  domainSupported="true|false" />

          說明:指定應(yīng)用程序通過服務(wù)器的那些請求。
          有下列methodNames
          REGISTER
          SUBSCRIBE
          NOTIFY
          BENOTIFY
          ACK
          BYE
          INVITE
          OPTIONS
          MESSAGE
          SERVICE
          INFO
          REFER
          OTHER
          1.3.4
          <lc:responseFilter reasonCodes="RESPONSE_CLASSES|ALL|NONE" />

          說明:定義應(yīng)用程序通過服務(wù)器響應(yīng)那個類別。
          類別如下:
          1XX
          2XX
          3XX
          4XX
          5XX
          6XX
          1.3.5
           <lc:file path="filePath"  keyColumnName=[columName] delimitedBy="comma/tab/whitespace"
                        <column name
          ="columnName"/>
           
          <lc:column name="ColumnName"/>

          </lc:file>

          說明:Name屬性指引用的text文件名稱,必須是有效的MSPL。Path屬性是這個文件的決對路徑,如果是相對的,它必須是相對于運行RTCSRV.exe的路徑。
          1.3.6
          <lc:column name="columnName"

          用這個標(biāo)簽可以指定一個或多個列節(jié)點。

          2. Microsoft SIP Processing Language
                 MSPL是用來過濾或路由SIP消息的腳本語言,像大家知道的"message filters",這個腳本是植入到application manifests里的LCS應(yīng)用程序中。
          MSPL不支持:
          Explicit (declarative) data types
          Type casting
          Pointers
          Declarations (other than basic function declarations, as detailed below)
          Arithmetic operations
          Iteration statements
          Preprocessor statements
          Attributes
          Static or global variables (state is not maintained across script invocations)
          2.1 MSPL Script Syntax
          2.1.1 Function Invocation
           一個函數(shù)在MSPL里是唯一的,在MSPL里函數(shù)用如下語法格式來定義:
          function ParseDisplayName (displayName) 
                         }

          所有的函數(shù)定義必須在消息過濾腳本的開始處,在過濾腳本之前。一個函數(shù)能有零個或更多的參數(shù)。為了防止無意中的循環(huán),遞歸函數(shù)的調(diào)用是不允許的。互相的遞歸調(diào)用calls-calls模式也是不允許的。例如,如果函數(shù)1調(diào)用函數(shù)2,然后調(diào)用函數(shù)3,函數(shù)3不能調(diào)用1或2的任意一個。返回值類型是implicitly defined的,更確切的說,這個類型是傳遞的返回聲明的值決定的。參數(shù)也是implicitly defined的。函數(shù)不能返回collections,它支持的的返回類型有strings,bools,integers和floats.
          下面的函數(shù)示例過濾了一個特殊的string,如果這個string被找到返回true,否則,返回false.
                         function FilterString (content) 
                         
          {
                                        filterWord 
          ="confidential"

                                         
          return ContainsString(content, filterWord, true
          );
                         }
          2.1.2 The foreach Statement
                 在SIP消息處理過程中foreach允許腳本編寫者比較句柄collections,例如contact header collections和 endpoint collections。下面示例演示了foreach loop的語法構(gòu)成。
                 foreach (element in expression) statement
          For example:
                         
          foreach (dbEndpoint in

                         QueryEndpoints(
          "someone@example.com"))  }
                 這段代碼將求出collections里的值,Strings和其他unary types 像single-item collections一樣的處理。
          2.1.3 The break Statement
          Break 的用法和C#中switch/case里的用法相同
          2.1.4 The null Keyword
          Null關(guān)鍵字,腳本語法能添加一個null關(guān)鍵字,與empty string ("")不同,empty string是不能建立的。有下列函數(shù)將返回一個null來表明值沒有找到或者錯誤。
          " GetDisplayName
          " GetHostName
          " GetParameterValue
          " GetScheme
          " GetUri
          " GetUriParameter
          " GetUserName
          " GetUserAtHost
          " GetXMLAttr
          " QueryHomeServer
          另外,Message.Stamp 和 Message.StampPool也返回null.

          要:本文檔將介紹從最初建造一個application manifest到最終安裝和管理SIP application的詳細(xì)過程,并提供示例代碼,以演示開發(fā)擴展LCS應(yīng)用的具體方法。


          Live Communications Server Application API應(yīng)用
          1 在新的服務(wù)器布局里開發(fā)應(yīng)用程序
          Live Communications Server 2005支持新的服務(wù)器角色,包括:Standard Edition, Enterprise Edition, Enterprise Edition Pool, Enterprise Edition Back End Storage, Archiving Service, Director, Proxy, and Access Proxy。第三方應(yīng)用程序能配置到上述任意或全部服務(wù)器上,以滿足想得到的功能性。理解每個新的服務(wù)器角色的功能是開發(fā)和設(shè)計應(yīng)用程序的要點。
          2 建立一個Application Manifest
          以LCS默認(rèn)核心消息過濾腳本為例(此腳本原始位置:..\Program Files\Microsoft LC 2005\Server\ routing.am):
          這個MSPL腳本過濾引入的SIP消息,并且以端點ID(EDID)、可用性合計、活動性數(shù)值和AgeOfPresence數(shù)值為基礎(chǔ),嘗試為每一個消息選擇出最好的端點。端點沒有注冊存在或者可用性合計小于100的將不被考慮。
          示例代碼

          <?xml version="1.0">
          <lc:applicationManifest
           lc:appUri="http://www.my_domain_here.com/DefaultRoutingScript"
           xmlns:lc="http://schemas.microsoft.com/lc/2003/05">
          <lc:requestFilter methodNames="INVITE,MESSAGE,INFO,REFER,ACK,BYE,OTHER" 
                                  strictRoute="false" 
                                  registrarGenerated="true"
                                  domainSupported="true"/ >
          <lc:responseFilter reasonCodes="NONE" />
          <lc:proxyByDefault action="true" />
          <lc:scriptOnly />
          <lc:splScript><![CDATA[
              //Log函數(shù)向LCS指定Server Log寫入調(diào)試Log,具體內(nèi)容除消息內(nèi)容之外的全部消息。 
              Log( "Debug", 1, "we have a request - ", sipRequest.Method );

          //Ge tUri方法返回消息頭中的“To”
          toUri = GetUri( sipRequest.To );
          //Concatenate方法將用GetUserName得到的Sip中的toUri與@與GetHostName中的HostName
          //組合成toUserAtHost
              toUserAtHost = Concatenate( GetUserName( toUri ), "@", GetHostName( toUri ) );

          // rameterValue方法返回消息頭重指定的參數(shù)”EPID”的值。
              requestEPID = GetParameterValue( sipRequest.To, "EPID" );

           //定義變量并賦初值
          bestEPID = "";
              bestAgeOfPresence = 0x7FFFFFFF;
              bestAvailability = 0;
              bestActivity = 0;
              bestContactInfo = "";
              Log( "Debug", 1, "EPID - ", requestEPID );
          Log( "Debug", 1, "toUserAtHost - ", toUserAtHost );
          //循環(huán)全部端點
              foreach (dbEndpoint in QueryEndpoints( toUserAtHost, true )) {
                  Log( "Debug", 1, "    endpoint.EPID - ", dbEndpoint.EPID );
                  Log( "Debug", 1, "    endpoint.HasPresence - ", dbEndpoint.HasPresence );
                  Log( "Debug", 1, "    endpoint.Availability - ", dbEndpoint.Availability );
                  Log( "Debug", 1, "    endpoint.Activity - ", dbEndpoint.Activity );
                  Log( "Debug", 1, "    endpoint.AgeOfPresence - ", dbEndpoint.AgeOfPresence );
                  Log( "Debug", 1, "    endpoint.ContactInfo - ", dbEndpoint.ContactInfo );

           // 第一步,用SupportsMethod函數(shù)確定SIP方法是否被應(yīng)用程序支持。
                  if (!SupportsMethod( sipRequest.Method, dbEndpoint.StandardMethods, dbEndpoint.ExtraMethods )) {
            //跳出這個端點,因為不能處理請求的方法。
                      Log( "Debug", 1, "        * skipped because of method" );
                      continue;
                      }
                  if (requestEPID != "") {
                      if (requestEPID == dbEndpoint.EPID) {
                 //這個請求已經(jīng)把一個能處理這個方法的端點當(dāng)作目標(biāo),所以用這個端點。
                          Log( "Debug", 1, "        * matched EPID" );
           //給前面定義的變量賦值
                          bestContactInfo = dbEndpoint.ContactInfo;
                          break;
                      }
                      else {
           //請求已確定EPID,但不匹配,跳出這個端點,繼續(xù)執(zhí)行。
                          Log( "Debug", 1, "        * skipped because of EPID" );
                          continue;
                      }
                  }

                  if (!dbEndpoint.HasPresence ||
                      dbEndpoint.Availability < 100 ||
                      dbEndpoint.ContactInfo == ""
                     ) {
                      //如果在ContactInfo字段中沒有在線,或者狀態(tài)為“offline”,或者沒有路由信息,跳出這個端點
                       Log( "Debug", 1, "        * skipped because of presence, activity or contactinfo" );
                      continue;
                  }

                  if (dbEndpoint.Availability < bestAvailability) {
                      //如果沒有可用性條出這個端點
                      Log( "Debug", 1, "        * skipped because of availability" );
                      continue;
                  }

                  if (dbEndpoint.Availability == bestAvailability) {
                      if (dbEndpoint.Activity < bestActivity) {
                          //如果這個端點活躍性小于1,跳出這個端點
                          Log( "Debug", 1, "        * skipped because of activity" );
                          continue;
                          }
          ……(略)

          3 為Live Communications Server 創(chuàng)建一個SIP應(yīng)用程序
          3.1 Setting up a Server Agent
          server agent是你的應(yīng)用程序和LCS之間的公共點。它是用ServerAgent類定義的對象,由它通過LCS代表你的應(yīng)用程序發(fā)送和接收消息。
          配置一個 LCS Agent的第一步是建立一個application manifest并編譯。這個application manifest將要運行在服務(wù)器上并且通過消息過濾腳本僅接收你的應(yīng)用程序感興趣的SIP消息。這個動作是通過執(zhí)行你的應(yīng)用程序的Main方法實現(xiàn)的。例如下面代碼:
          using System.Threading;
          using System.Resources;
          using Microsoft.Rtc.Sip;


          // 在這個例子中獲取包含你的application manifest的XML string,
          // 這個XML string //像資源一樣包含在應(yīng)用程序裝配件中,用 
          // ResourceManager.GetString(resourceName)方法得到。

          ResourceManager myResourceManager 
          = new ResourceManager(myApplicationClass);

          //” appManifest”是你的application manifest XML 文件的名字,像添加應(yīng)用程序// 的資源一樣的添加它。

          string myAppManifestXmlString = myResourceManager.GetString("appManifest");

          ApplicationManifest myAppManifest 
          = new ApplicationManifest(myAppManifestXmlString);
           
          try {
          //編譯
           myAppManifest.Compile();
          }

          //異常處理
          catch (CompilerErrorException cee) {
           Console.WriteLine(
          "The following errors occurred during compilation:");
           
          foreach (string errorMessage in cee.ErrorMessages) {
              Console.WriteLine(
          "--- {0}"
          , errorMessage);
           }

          }

           

          在實例化ServerAgent的時候提供ApplicationManifest對象,ServerAgent的構(gòu)造函數(shù)會編譯這個Application Manifest.例如下面代碼。

          try {
           ServerAgent myAppServerAgent 
          = new
           ServerAgent(myAppManifest);
          }
           
          catch (NullReferenceException nre) 
          {
           Console.WriteLine(
          "The application manifest is uncompiled and ServerAgent cannot be instantiated."
          );
          }
           
          catch (ServerNotFoundException snfe) 
          {
           Console.WriteLine(
          "The Live Communications Server is not available."
          );
          }

           

          應(yīng)用程序必須從消息過濾中分配句柄信息,同時,還必須建立一個類和這個句柄的方法對應(yīng)。例如下面代碼,如果你有一個call在你的消息過濾器里。
          Dispatch("OnInviteReceived");
          在你的定義的類上必須有一個相應(yīng)的OnInviteReceived方法。


          3.2 Processing Server Events
          當(dāng)Dispatch被腳本呼叫過,一個服務(wù)器事件便被觸發(fā)。
          3.3 Handling Messages from the Live Communications Server
          當(dāng)LCS收到消息,application manifest必須有特定的轉(zhuǎn)發(fā)給相應(yīng)得應(yīng)用程序。
          例如在application manifest中有下列代碼:

          if (sipRequest.Method == "MESSAGE")
           Dispatch(
          "OnMessageReceived"
          );
           Respond(
          200
          );
          }


          上述代碼功能是, 當(dāng)LCS分配SIP消息類型為“MESSAGE”的消息給“OnMessageReceived”你的應(yīng)用程序的事件句柄,定義事件句柄的代碼示例如下:

          public void OnMessageReceived(object sender, RequestReceivedEventArgs requestEventArgs) {

           
          // Obtain the Request object to process from RequestReceivedEventArgs.

           Request request = requestEventArgs.Request;
           
           
          // Obtain the new server transaction for this request.

           ServerTransaction myServerTransaction = requestEventArgs.ServerTransaction;

           
          //
           Processing logic here.
           
          //
           

           
          // Create a branch on the server transaction to forward the request.

           try
           
          {
              
          // Attempt to send the request.

              requestEventArgs.ServerTransaction.CreateBranch();
              requestEventArgs.SendRequest(request);
           }

           
          catch (Exception e)
           
          {
              Console.WriteLine(
          "Unexpected exception: {0}\n{1}"

                                      e.Message,
                                      e.StackTrace);
           }
           
          }


          參考文檔《Microsoft Office Live Communications Server 2005》 
          主站蜘蛛池模板: 岢岚县| 浮梁县| 鹿泉市| 黄骅市| 莆田市| 华阴市| 项城市| 左权县| 沁阳市| 荣昌县| 浦北县| 梅州市| 宣威市| 甘孜| 富平县| 仲巴县| 廉江市| 宁远县| 民权县| 罗田县| 玉林市| 壶关县| 桃园市| 隆回县| 清水河县| 邯郸县| 蒙山县| 广宗县| 云浮市| 涿州市| 庆元县| 麻江县| 微博| 濉溪县| 崇信县| 托里县| 军事| 满洲里市| 突泉县| 内丘县| 广宗县|