この章では、SIPアプリケーションのプログラミングについて説明します。内容は次のとおりです。
この項では、Oracle WebLogic Server SIP Container SipServletMessageインタフェースおよび構成パラメータを使用して、SIPメッセージ・ヘッダー・フォーマットを制御する方法について説明します。
ワイヤレス・ネットワークで動作するアプリケーションでは、メッセージのサイズを縮小して帯域を節約するために、SIPヘッダーのサイズを制限できます。JSR 289のSipServletMessage.setHeaderメソッドを使用すると、アプリケーション開発者は所定のヘッダーの値に長いまたは圧縮されたフォーマットを設定できます。
JSR 289で提供されたSipServletMessage APIの機能の1つは、setHeaderFormメソッドを使用してSIPメッセージ全体に長いヘッダまたは圧縮ヘッダー・フォーマットを設定できることです。
WlssSipServletMessageに加え、Oracle WebLogic Server SIP Containerには、システムで生成されたすべてのヘッダーに対してSIPヘッダー・フォーマットを制御できるコンテナ全体の構成パラメータが用意されています。このシステム全体のパラメータをWlssSipServletMessage.setUseHeaderFormおよびSipServletMessage.setHeaderとともに使用してヘッダー・フォーマットをさらにカスタマイズできます。
表3-1は、SIP仕様(http://www.ietf.org/rfc/rfc3261.txt)に説明されている圧縮ヘッダーの省略形を定義しています。追加ヘッダーを説明する仕様には、圧縮ヘッダーの省略形が含まれることもあります。
メッセージで使用されるヘッダー・フォーマットの割当ておよび取得には、setHeaderFormやgetHeaderFormのようなgetter/setterメソッドのペアを使用します。これらのメソッドは、ヘッダー・フォーマットを説明する単純な列挙オブジェクトであるHeaderFormオブジェクトを割り当てたり返したりします。
COMPACT - メッセージのすべてのヘッダーに圧縮フォーマットを使用するように強制します。この動作は、構成リファレンス・マニュアルのuse-compact-formに説明した「force compact」のコンテナ全体の構成値と同じです。
LONG - メッセージのすべてのヘッダーに対して長いフォーマットを使用するように強制します。この動作は、構成リファレンス・マニュアルのuse-compact-formに説明した「force long」のコンテナ全体の構成値と同じです。
DEFAULT — use-compact-formに設定されたコンテナ全体の構成値にヘッダー・フォーマットを指定します。
SipServletResponse.setHeaderFormはSipServletMessage.setHeaderとコンテナ・レベルの構成パラメータuse-compact-formと組み合せて使用できます。
ヘッダー・フォーマットは、ヘッダー、メッセージおよびSIPサーブレット・コンテナ・レベルで設定できます。表3-1は、SipServletMessage.setHeaderForm.で様々なコンテナ構成およびメッセージ・レベルが設定されている場合に、SipServletMessage.setHeaderで新しいヘッダーを追加するときのヘッダー・フォーマットを示しています。
表3-2 ヘッダーを追加する時のAPIの動作
| 
 SIPサーブレット・コンテナ・ヘッダー構成(  | 
 .SIPServletMessage setHeaderFormの設定  | 
 SipServletMessage. setHeaderの値  | 
 取得したヘッダー  | 
| 
 COMPACT  | 
 DEFAULT  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 COMPACT  | 
 DEFAULT  | 
 「c」  | 
 「c」  | 
| 
 COMPACT  | 
 COMPACT  | 
 「Content-Type」  | 
 「c」  | 
| 
 COMPACT  | 
 COMPACT  | 
 「c」  | 
 「c」  | 
| 
 COMPACT  | 
 LONG  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 COMPACT  | 
 LONG  | 
 「c」  | 
 「Content-Type」  | 
| 
 LONG  | 
 DEFAULT  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 LONG  | 
 DEFAULT  | 
 「c」  | 
 「c」  | 
| 
 LONG  | 
 COMPACT  | 
 「Content-Type」  | 
 「c」  | 
| 
 LONG  | 
 COMPACT  | 
 「c」  | 
 「c」  | 
| 
 LONG  | 
 LONG  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 LONG  | 
 LONG  | 
 「c」  | 
 「Content-Type」  | 
| 
 FORCE_COMPACT  | 
 DEFAULT  | 
 「Content-Type」  | 
 「c」  | 
| 
 FORCE_COMPACT  | 
 DEFAULT  | 
 「c」  | 
 「c」  | 
| 
 FORCE_COMPACT  | 
 COMPACT  | 
 「Content-Type」  | 
 「c」  | 
| 
 FORCE_COMPACT  | 
 COMPACT  | 
 「c」  | 
 「c」  | 
| 
 FORCE_COMPACT  | 
 LONG  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 FORCE_COMPACT  | 
 LONG  | 
 「c」  | 
 「Content-Type」  | 
| 
 FORCE_LONG  | 
 DEFAULT  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 FORCE_LONG  | 
 DEFAULT  | 
 「c」  | 
 「Content-Type」  | 
| 
 FORCE_LONG  | 
 COMPACT  | 
 「Content-Type」  | 
 「c」  | 
| 
 FORCE_LONG  | 
 COMPACT  | 
 「c」  | 
 「c」  | 
| 
 FORCE_LONG  | 
 LONG  | 
 「Content-Type」  | 
 「Content-Type」  | 
| 
 FORCE_LONG  | 
 LONG  | 
 「c」  | 
 「Content-Type」  | 
表3-1は、コンテナ構成値が異なる場合に、WlssSipServletResponse.setUseHeaderFormでヘッダー・フォーマットを設定したときのシステム・ヘッダー・フォーマットを示しています。
表3-3 システム・ヘッダーに対するAPIの動作
| 
 SIPサーブレット・コンテナ・ヘッダー構成(  | 
 SipServletMessage. setHeaderFormの設定  | 
 取得した コンタクト・ヘッダー  | 
| 
 COMPACT  | 
 DEFAULT  | 
 「m」  | 
| 
 COMPACT  | 
 COMPACT  | 
 「m」  | 
| 
 COMPACT  | 
 LONG  | 
 「Contact」  | 
| 
 LONG  | 
 DEFAULT  | 
 「Contact」  | 
| 
 LONG  | 
 COMPACT  | 
 「m」  | 
| 
 LONG  | 
 LONG  | 
 「Contact」  | 
| 
 FORCE_COMPACT  | 
 DEFAULT  | 
 「m」  | 
| 
 FORCE_COMPACT  | 
 COMPACT  | 
 「m」  | 
| 
 FORCE_COMPACT  | 
 LONG  | 
 「Contact」  | 
| 
 FORCE_LONG  | 
 DEFAULT  | 
 「Contact」  | 
| 
 FORCE_LONG  | 
 COMPACT  | 
 「m」  | 
| 
 FORCE_LONG  | 
 LONG  | 
 「Contact」  | 
この項では、SIPメッセージ本文で指定されている間接的なコンテンツを扱うことのできるSIP Servletの開発方法について説明します。
SIPメッセージのボディで提供するデータは、SIPメッセージ・ボディに直接含めることも、間接的に含めることもできます。後者の場合は、URLコンテンツを示すHTTP URLとメタデータを指定するという方法を使用します。メッセージ・ボディのコンテンツを間接的に指定するという方法は、主に次の状況で使用されます。
メッセージ・ボディに含まれるデータの量が多い場合。この場合は、コンテンツの間接化を行うことで、大きなデータを(別の接続またはプロトコルを使用して) SIPネットワークの外部に移動させることができます。
帯域幅に制約があるアプリケーションの場合。この場合は、コンテンツの間接化を行うことで、メッセージ本文を取得すべきかどうかをアプリケーションがメタデータに基づいて判断できるようになります(メッセージ本文の取得は、アプリケーションのパフォーマンスやレスポンス時間を低下させる可能性があります)。
Oracle WebLogic Server SIP Containerには、SIPメッセージ内に指定されている間接的なコンテンツを取り扱うための単純なAPIが用意されています。
Oracle WebLogic Server SIP Containerのコンテンツ間接化APIを使用すると、SIPメッセージでコンテンツの間接化が行われているかどうかをすばやく判断したり、間接的なコンテンツに関連付けられているすべてのメタデータを簡単に取得したりできます。この基本APIは、ユーティリティ・クラスcom.bea.wcp.sip.engine.server.ContentIndirectionUtilと、コンテンツ・メタデータのアクセスに使用するインタフェースcom.bea.wcp.sip.engine.server.ICParsedDataから成ります。
SIPサーブレットでは、このユーティリティ・クラスを使用することで、間接的なコンテンツを含んでいるSIPメッセージを識別したり、コンテンツ・メタデータを表すICParsedDataオブジェクトを取得したりできます。ICParsedDataオブジェクトには、様々なメタデータ属性を返す単純なゲッター・メソッドが用意されています。
この項では、Oracle WebLogic Server SIP ContainerのSipServletSnmpTrapRuntimeMBeanを使用してSIP サーブレット内からSNMPトラップを生成する方法について説明します。
Oracle WebLogic Server SIP Containerでは、実行時MBeanとしてSipServletSnmpTrapRuntimeMBeanが含まれており、これを使用することで、アプリケーションでSNMPトラップを簡単に生成できます。Oracle WebLogic Server SIP ContainerのMIBには、アプリケーションによって生成されるトラップ用に予約された7個の新しいOIDが含まれます。それぞれのOIDはアプリケーションがトラップに割り当てる重大度に対応しており、重大度の最も低いものから順番に並べると次のようになります。
Info
Notice
Warning
Error
Critical
Alert
Emergency
アプリケーションからトラップを生成するには、SipServletSnmpTrapRuntimeMBeanのインスタンスを取得して、目的のトラップの重大度に対応するメソッドを実行します(sendInfoTrap()、sendWarningTrap()、sendErrorTrap()、sendNoticeTrap()、sendCriticalTrap()、sendAlertTrap()、sendEmergencyTrap())。各メソッドにはパラメータが1つあり、このパラメータには生成するトラップ・メッセージの文字列値を指定します。
この方法でSNMPトラップを生成すると、Oracle WebLogic Server SIP Containerは自動的に、サーブレット名、アプリケーション名および呼出し側サーブレットに関連付けられているOracle WebLogic Server SIP Containerインスタンスの名前を送信します。
SipServletSnmpTrapRuntimeMBeanを取得するには、呼出し側のSIPサーブレットがサーブレット・コンテキストからMBeanルックアップを実行できる必要があります。この機能を有効化するには、Oracle WebLogic Server SIP Container管理者のrole-nameエントリをsip.xmlデプロイメント記述子内のsecurity-roleとrun-asロール要素に割り当てる必要があります。例3-1に、必須ロール要素を強調表示したsip.xmlファイルのサンプルを示します。
例3-1 sip.xmlでのロール要件のサンプル
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sip-app
   PUBLIC "-//Java Community Process//DTD SIP Application 1.0//EN"
   "http://www.jcp.org/dtd/sip-app_1_0.dtd">
<sip-app>
  <display-name>My SIP Servlet</display-name>
  <distributable/>
  <servlet>
    <servlet-name>myservlet</servlet-name>
    <servlet-class>com.mycompany.MyServlet</servlet-class>
    <run-as>
      <role-name>weblogic</role-name>
    </run-as>
  </servlet>
  <servlet-mapping>
    <servlet-name>myservlet</servlet-name>
    <pattern>
      <equal>
        <var>request.method</var>
        <value>INVITE</value>
      </equal>
    </pattern>
  </servlet-mapping>
  <security-role>
    <role-name>weblogic</role-name>
  </security-role>
</sip-app>
SNMPトラップを発生するSIPサーブレットはすべて、最初にSipServletSnmpTrapRuntimeMBeanへの参照を取得する必要があります。例3-2に、MBeanを取得するメソッドのサンプル・コードを示します。
例3-2 SipServletSnmpTrapRuntimeMBeanにアクセスするメソッドのサンプル
public SipServletSnmpTrapRuntimeMBean getServletSnmpTrapRuntimeMBean() {
    MBeanHome localHomeB = null;
    SipServletSnmpTrapRuntimeMBean ssTrapMB = null;
    try
    {
      Context ctx = new InitialContext();
      localHomeB = (MBeanHome)ctx.lookup(MBeanHome.LOCAL_JNDI_NAME);
      ctx.close();
    } catch (NamingException ne){
      ne.printStackTrace();
    }
    Set set = localHomeB.getMBeansByType("SipServletSnmpTrapRuntime");
    if (set == null || set.isEmpty()) {
      try {
        throw new ServletException("Unable to lookup type 'SipServletSnmpTrapRuntime'");
      } catch (ServletException e) {
        e.printStackTrace();
      }
    }
    ssTrapMB = (SipServletSnmpTrapRuntimeMBean) set.iterator().next();
    return ssTrapMB;
}
例3-3は、例3-2のメソッドを使用して、SIP INVITEへのレスポンス時にMBeanインスタンスを通じてSIPサーブレットからSNMPトラップを生成する方法を示しています。
例3-3 SNMPトラップの生成
public class MyServlet extends SipServlet {
  private SipServletSnmpTrapRuntimeMBean sipServletSnmpTrapMb = null;
  public MyServlet () {
  }
  public void init (ServletConfig sc) throws ServletException {
    super.init (sc);
    sipServletSnmpTrapMb = getServletSnmpTrapRuntimeMBean();
  }
  protected void doInvite(SipServletRequest req) throws IOException {
    sipServletSnmpTrapMb.sendInfoTrap("Rx Invite from " + req.getRemoteAddr() + "with call id" + req.getCallId());
  }
}