C でのメッセージ処理ノードまたは出力ノードの作成

始める前に

ロード可能インプリメンテーション・ライブラリー、または LIL、 は C ノード (またはパーサー) のインプリメンテーション・モジュールです。 LIL はダイナミック・リンク・ライブラリー (DLL) としてインプリメントされます。 これにはファイル拡張子 .dll は付けられず、.lil が付けられます。

開発者が作成する必要のあるインプリメンテーション関数は、C ノード・インプリメンテーション関数でリストしています。このプロセスに役立てるために WebSphere Message Broker によって提供されるユーティリティー関数は、C ノード・ユーティリティー関数でリストしています。

WebSphere Message Broker では、SwitchNode および TransformNode という名前の 2 つのサンプル・ユーザー定義ノードのソースが準備されています。 これらのノードは現行の状態で使用することもできますし、変更を加えてもかまいません。 さらに、ユーザー定義拡張 (User-defined Extension)のサンプルを使用することもできます。

概念上、メッセージ処理ノードは何らかの形でメッセージを処理するために使用され、 出力ノードはメッセージをビット・ストリームとして出力するために使用されます。 しかし、メッセージ処理ノードや出力ノードをコーディングするとき、 これらは基本的に同じものです。 出力ノードでメッセージ処理を実行することもできますし、同様に、メッセージ処理ノードを使用してメッセージをビット・ストリームとして出力することもできます。 単純化するため、 このトピックではメッセージ処理ノードとしてノードを主に参照していますが、 どちらのタイプのノードの機能についても取り上げます。

ブローカーへのノードの宣言

以下の手順は、ノードをブローカーへ宣言する方法を表しています。

  1. LIL がロードされ、オペレーティング・システムによって初期化されると、 ブローカーによって初期化関数 bipGetMessageflowNodeFactory が呼び出されます。 これはブローカーの構成スレッドから呼び出されます。ブローカーは、 LIL が実行できる事柄と、ブローカーが LIL を呼び出す方法を理解するために、この関数を呼び出します。 たとえば、以下のようになります。
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. bipGetMessageflowNodeFactory 関数が、 ユーティリティー関数 cniCreateNodeFactory を呼び出します。 この関数は、LIL がサポートするすべてのノードのファクトリー名 (またはグループ名) を戻します。 たとえば、以下のようになります。
    {
     CciFactory* factoryObject;
     int rc = 0;
     CciChar factoryName[] = L"SwitchNodeFactory";
     CCI_EXCEPTION_ST exception_st;
    
     /* Create the Node Factory for this node */
     factoryObject = cniCreateNodeFactory(0, factoryName);
     if (factoryObject == CCI_NULL_ADDR) {
      if (rc == CCI_EXCEPTION) {
       /* Get details of the exception */
       cciGetLastExceptionData(&rc, &exception_st);
    
       /* Any local error handling can go here */
    
       /* Rethrow the exception */
       cciRethrowLastException(&rc);
      }
    
      /* Any further local error handling can go here */
     }
     else {
      /* Define the nodes supported by this factory */
      defineSwitchNode(factoryObject);
     }
    
     /* Return address of this factory object to the broker */
     return(factoryObject);
    }

    この例では、UTF-16 のトレース情報が必要な場合は、CCI_EXCEPTION_ST を CCI_EXCEPTION_WIDE_ST に置換して、cciGetLastExceptionDatacciGetLastExceptionDataW に置換する必要があります。

メッセージ処理ノードとしてのノードの定義

LIL は次にユーティリティー関数 cniDefineNodeClass を呼び出して、 各ノードの名前と、インプリメンテーション関数のアドレスの仮想関数表を渡します。 たとえば、 SwitchNode という名前の単一のノードとその関数表を定義するには、 次のようにします。
void defineSwitchNode(void* factoryObject){
 static CNI_VFT vftable = {CNI_VFT_DEFAULT};

 /* Setup function table with pointers to node implementation functions */
 vftable.iFpCreateNodeContext = _createNodeContext;
 vftable.iFpDeleteNodeContext = _deleteNodeContext;
 vftable.iFpGetAttributeName2 = _getAttributeName2;
 vftable.iFpSetAttribute      = _setAttribute;
 vftable.iFpGetAttribute2     = _getAttribute2;
 vftable.iFpEvaluate          = _evaluate;

 cniDefineNodeClass(0, factoryObject, L"SwitchNode", &vftable);

 return;
}
これは構成スレッドから呼び出されます。

ユーザー定義ノードは、cniEvaluate 関数をインプリメントすることによって、 メッセージ処理または入力ノードの機能を提供するという役割を果たします。 ユーザー定義ノードは、 cniEvaluate インプリメンテーションか cniRun インプリメンテーションのいずれか、 または両方をインプリメントしていなければなりません。 そうでないと、ブローカーはそのユーザー定義ノードをロードせず、 cniDefineNodeClass ユーティリティー関数が失敗して、 CCI_MISSING_IMPL_FUNCTION が戻されます。

ユーザー定義メッセージ処理ノードが含まれたメッセージ・フローが正常にデプロイされていれば、 メッセージ・フローに渡される各メッセージごとに、 そのノードの cniEvaluate 関数が呼び出されます。

メッセージ・フロー・データがノードの入力ターミナルで受信されます。 メッセージ・フロー・データとは、メッセージ、グローバル環境、ローカル環境、および例外リストです。

以下に例を示します。
void cniEvaluate(
  CciContext* context,
  CciMessage* destinationList,
  CciMessage* exceptionList,
  CciMessage* message
){                                    
  ...
}

ノードのインスタンスの作成

以下の手順は、ノードをインスタンス化する方法を表しています。

  1. ブローカーは、関数ポインターの表を受信すると、 ユーザー定義ノードの各インスタンス化ごとに関数 cniCreateNodeContext を呼び出します。 ユーザー定義ノードを使用する 3 つのメッセージ・フローがある場合は、 3 つのそれぞれに対して cniCreateNodeContext 関数が呼び出されます。 この関数は、そのユーザー定義ノードのインスタンス化用に、 構成された属性の値を保持するためのメモリーを割り振ります。 たとえば、以下のようになります。
    1. ユーザー関数 cniCreateNodeContext が呼び出されます。
      CciContext* _Switch_createNodeContext(
        CciFactory* factoryObject,
        CciChar*    nodeName,
        CciNode*    nodeObject
      ){
        static char* functionName = (char *)"_Switch_createNodeContext()";
        NODE_CONTEXT_ST* p;
        CciChar          buffer[256];
      
      
    2. ローカル・コンテキストにポインターを割り振り、コンテキスト・エリアを消去します。
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
      
        if (p) {
           memset(p, 0, sizeof(NODE_CONTEXT_ST));
    3. コンテキストの中のノード・オブジェクト・ポインターを保存します。
         p->nodeObject = nodeObject;
    4. ノード名を保存します。
       CciCharNCpy((CciChar*)&p->nodeName, nodeName, MAX_NODE_NAME_LEN);
  2. ブローカーが適切なユーティリティー関数を呼び出して、 ノードの入力ターミナルと出力ターミナルについての情報を検出します。 ノードには、 いくつかの入力ターミナルと出力ターミナルが関連付けられています。 ユーザー関数 cniCreateNodeContext 内で、 cniCreateInputTerminal および cniCreateOutputTerminal への呼び出しがなされ、 ユーザー・ノードのターミナルが定義されます。 これらの関数は、cniCreateNodeContext インプリメンテーション関数内で呼び出されなければなりません。 たとえば、1 つの入力ターミナルと 2 つの出力ターミナルを持つノードを定義するには、 次のようにします。
        {
          const CciChar* ucsIn = CciString("in", BIP_DEF_COMP_CCSID) ;
          insInputTerminalListEntry(p, (CciChar*)ucsIn);
          free((void *)ucsIn) ;
        }
        {
          const CciChar* ucsOut = CciString("out", BIP_DEF_COMP_CCSID) ;
          insOutputTerminalListEntry(p, (CciChar*)ucsOut);
          free((void *)ucsOut) ;
        }
        {
          const CciChar* ucsFailure = CciString("failure", BIP_DEF_COMP_CCSID) ;
          insOutputTerminalListEntry(p, (CciChar*)ucsFailure);
          free((void *)ucsFailure) ;
        }

属性の設定

属性は、ブローカーを開始するとき、 あるいは新しい値を持つメッセージ・フローを再デプロイするときに設定します。 構成スレッド上のユーザー・コードを呼び出すブローカーによって、属性が設定されます。 そのユーザー・コードでは、後にメッセージを処理するときに使用するために、 そのノードのコンテキスト・エリアにこれらの属性を保管する必要があります。

入力ターミナルと出力ターミナルの作成後、 ブローカーは cniSetAttribute 関数を呼び出して、 このユーザー定義ノードのインスタンス化用に構成されている属性の値を渡します。 以下に例を示します。
    {
      const CciChar* ucsAttr = CciString("nodeTraceSetting", BIP_DEF_COMP_CCSID) ;
      insAttrTblEntry(p, (CciChar*)ucsAttr, CNI_TYPE_INTEGER);
      _setAttribute(p, (CciChar*)ucsAttr, (CciChar*)constZero);
      free((void *)ucsAttr) ;
    }
    {
      const CciChar* ucsAttr = CciString("nodeTraceOutfile", BIP_DEF_COMP_CCSID) ;
      insAttrTblEntry(p, (CciChar*)ucsAttr, CNI_TYPE_STRING);
      _setAttribute(p, (CciChar*)ucsAttr, (CciChar*)constSwitchTraceLocation);
      free((void *)ucsAttr) ;
    }

ノード機能のインプリメント

ブローカーがキューからメッセージを取り出し、 そのメッセージがユーザー定義のメッセージ処理ノードまたは出力ノードの入力ターミナルに到着すると、 ブローカーはインプリメンテーション関数 cniEvaluate を呼び出します。 この関数はメッセージ処理スレッド上に呼び出され、メッセージを使用して何を行うかを決定します。 特に追加のインスタンスが使用される場合に、この関数はマルチスレッド上に呼び出される場合もあります。

メッセージ処理ノードのインスタンスの削除

ノードのインスタンスを削除するには、 cniDeleteNodeContext 関数を使用します。 たとえば、以下のようになります。

void _deleteNodeContext(
  CciContext* context
){
  static char* functionName = (char *)"_deleteNodeContext()";

  return;
}

cniDeleteNodeContext 関数はユーザーによって 提供され、メッセージ・フローが削除されたときにブローカーによって呼び出されます。

特記事項 | 商標 | ダウンロード | ライブラリー | サポート | フィードバック
Copyright IBM Corporation 1999, 2005 Last updated: 11/07/2005
as09980_