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

始める前に

WebSphere Message Broker では、SwitchNode および TransformNode という名前の 2 つのサンプル・ユーザー定義ノードのソースが準備されています。 これらのノードは現行の状態で使用することもできますし、変更を加えてもかまいません。 また、ユーザー定義ノード (C で作成された メッセージ処理ノードなど) の使用法を示すユーザー定義拡張機能のサンプルを 表示することもできます。

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

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

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

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

このトピックでは、両方のタイプのノードの機能について扱います。 以下のステップについて要約しています。
  1. ノードの宣言および定義
  2. ノードのインスタンスの作成
  3. 属性の設定
  4. ノード機能のインプリメント
  5. ノードのインスタンスの削除

ノードの宣言および定義

ブローカーに対してユーザー定義ノードを宣言して定義するには、初期化関数 bipGetMessageflowNodeFactory を LIL に含める必要があります。 以下のステップは、構成スレッド上で行われ、ブローカーが初期化関数をどのようにして呼び出し、初期化関数がユーザー定義ノードをどのようにして宣言および定義するかについての概要です。

  1. LIL がロードされ、オペレーティング・システムによって初期化されると、 ブローカーによって初期化関数 bipGetMessageflowNodeFactory が呼び出されます。 ブローカーは、 LIL が実行できる事柄と、ブローカーが LIL を呼び出す方法を理解するために、この関数を呼び出します。 例えば、以下のようになります。
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. bipGetMessageflowNodeFactory 関数は次にユーティリティー関数 cniCreateNodeFactory を呼び出します。 この関数は、LIL がサポートするすべてのノードのファクトリー名 (またはグループ名) を戻します。 ファクトリー名 (またはグループ名) は、そのブローカー内のすべての LIL で 固有でなければなりません。
  3. LIL は次にユーティリティー関数 cniDefineNodeClass を呼び出して、 各ノードの固有の名前と、インプリメンテーション関数のアドレスの仮想関数表を渡します。
    例えば、 以下のコードは MessageProcessingxNode という単一ノードの宣言と定義を行います。
    {
    CciFactory* factoryObject;
    int rc = 0;
    CciChar factoryName[] = L"MyNodeFactory";
    CCI_EXCEPTION_ST exception_st;
    
    /* Create the Node Factory for this node */
    factoryObject = cniCreateNodeFactory(0, factoryName);
    if (factoryObject == CCI_NULL_ADDR) {
    /* Any local error handling can go here */
    	}
    	else {
    /* Define the nodes supported by this factory */
    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"MessageProcessingxNode", &vftable);
    
    	}
    
    /* Return address of this factory object to the broker */
    return(factoryObject);
    }

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

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

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

    以下に例を示します。
    void cniEvaluate(
      CciContext* context,
      CciMessage* destinationList,
      CciMessage* exceptionList,
      CciMessage* message
    ){                                    
      ...
    }
    C ユーザー定義ノードのコンパイルに必要な最小コードについては、C のスケルトン・コードを参照してください。

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

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

  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);
    5. ノード・コンテキストを戻します。
      return (CciContext*) p;
  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) ;
        }
    C ユーザー定義ノードのコンパイルに必要な最小コードについては、C のスケルトン・コードを参照してください。

属性の設定

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

入力ターミナルと出力ターミナルの作成後、 ブローカーは 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) ;
    }
変更の始まりノードが持つことのできる構成属性の数には、制限がありません。 ただし、プラグイン・ノードは、基本構成属性としてすでにインプリメントされている属性をインプリメントしてはなりません。これらの基本属性は以下のとおりです。
  • label
  • userTraceLevel
  • traceLevel
  • userTraceFilter
  • traceFilter
変更の終わり

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

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

ノードのインスタンスの削除

ノードが削除される場合には、ブローカーは cniDeleteNodeContext 関数を呼び出します。 この関数は、ユーザー定義ノードが使用していたすべてのリソースを解放します。 例えば、以下のようになります。

void _deleteNodeContext(
  CciContext* context
){
  static char* functionName = (char *)"_deleteNodeContext()";
  free ((void*) context);  return;
}
特記事項 | 商標 | ダウンロード | ライブラリー | サポート | フィードバック
Copyright IBM Corporation 1999, 2006 最終更新: 08/21/2006
as09980_