WebSphere Message Broker バージョン 8.0.0.5 オペレーティング・システム: AIX、HP-Itanium、Linux、Solaris、Windows、z/OS

製品の最新バージョンについては、IBM Integration Bus バージョン 9.0 をご覧ください。

C での入力ノードの作成

メッセージ・フローにメッセージを受信するためのユーザー定義入力ノードを C で作成します。

始める前に

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

ノード用に作成するインプリメンテーション関数のリストは、C ノード・インプリメンテーション関数にあります。 ランタイム・ブローカーにインプリメントされたユーティリティー関数を呼び出して、ノード操作に役立てることもできます。これらの関数のリストは C ノード・ユーティリティー関数 にあります。

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

ノードの宣言および定義

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

  1. LIL がオペレーティング・システムによってロードされ、初期化されると、ブローカーによって初期化関数 bipGetMessageflowNodeFactory が呼び出されます。 ブローカーは、 LIL が実行できる事柄と、ブローカーが LIL を呼び出す方法を理解するために、この関数を呼び出します。 以下に例を示します。
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. bipGetMessageflowNodeFactory 関数はユーティリティー関数 cniCreateNodeFactory を呼び出す必要があります。 この関数は、LIL がサポートするすべてのノードに固有のファクトリー名 (またはグループ名) を戻します。 戻されるファクトリー名 (またはグループ名) はいずれも、単一のランタイム・ブローカー内のすべての LIL で固有でなければなりません。
  3. LIL はユーティリティー関数 cniDefineNodeClass を呼び出して、各ノードの固有の名前と、インプリメンテーション関数のアドレスの仮想関数表を渡す必要があります。
    例えば、 以下のコードは InputxNode という単一ノードの宣言と定義を行います。
    {
    	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.iFpRun               = _run;
    
    	cniDefineNodeClass(0, factoryObject, L"InputxNode", &vftable);
    	}
    
    	/* Return address of this factory object to the broker */
    	return(factoryObject);
    }

    ユーザー定義ノードは、cniRun インプリメンテーション関数をインプリメントすることによって、入力ノードのフィーチャーを提供するという役割を果たします。

    ユーザー定義ノードは、cniRun インプリメンテーション関数か cniEvaluate インプリメンテーション関数のいずれかをインプリメントしていなければなりません。 そうでないと、ブローカーはそのユーザー定義ノードをロードせず、cniDefineNodeClass ユーティリティー関数が失敗して、CCI_MISSING_IMPL_FUNCTION が戻されます。

    以下に例を示します。
    int cniRun(                       
      CciContext* context,                
      CciMessage* localEnvironment,        
      CciMessage* exceptionList,          
      CciMessage* message
    ){          
      ...
      /* Get data from external source */
      return CCI_SUCCESS_CONTINUE;                                    
    }
    定期的に戻り値を使用してブローカーに制御を返します。

    ユーザー定義入力ノードが含まれるメッセージ・フローが正常にデプロイされると、ノードがメッセージを取り出してメッセージ・フローの残りの部分に伝搬できるように、このノードの cniRun 関数が繰り返し呼び出されます。

    C ユーザー定義ノードのコンパイルに必要な最小コードについては、C のスケルトン・コードを参照してください。

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

ノードをインスタンス化するには、次のようにします。

  1. ブローカーは、関数ポインターの表を受信すると、 ユーザー定義ノードの各インスタンス化ごとに関数 cniCreateNodeContext を呼び出します。 例えば、3 つのメッセージ・フローがユーザー定義ノードを使用する場合、3 つのそれぞれに対して cniCreateNodeContext 関数が呼び出されます。 この関数は、そのユーザー定義ノードのインスタンス化用に、構成された属性の値を保持するためのメモリーを割り振ります。 以下に例を示します。
    1. cniCreateNodeContext 関数を呼び出します。
      CciContext* _createNodeContext(
        CciFactory* factoryObject,
        CciChar*    nodeName,
        CciNode*    nodeObject
      ){
        static char* functionName = (char *)"_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. 入力ノードには、いくつかの出力ターミナルが関連付けられますが、 通常は入力ターミナルはありません。 ノードをインスタンス化するときに、 ユーティリティー関数 cniCreateOutputTerminal を使用して、 入力ノードに出力ターミナルを追加します。 これらの関数は、cniCreateNodeContext インプリメンテーション関数内で呼び出されなければなりません。 例えば、 3 つの出力ターミナルを持つ入力ノードを定義するには、 次のようにします。
       {
          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) ;
        }    
        {
          const CciChar* ucsCatch = CciString("catch", BIP_DEF_COMP_CCSID) ;
          insOutputTerminalListEntry(p, (CciChar*)ucsCatch);
          free((void *)ucsCatch) ;    }
    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

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

入力ノードがあることをブローカーが認識している場合、 ブローカーは定期的にこのノードの cniRun 関数を呼び出します。 cniRun 関数は、実行すべきアクションを判断しなければなりません。 処理に使用できるデータがあれば、cniRun 関数はメッセージを伝搬できます。 処理に使用できるデータがなければ、cniRun 関数は CCI_TIMEOUT とともに制御を戻して、ブローカーが構成変更を続行できるようにします。

例えば、cniDispatchThread を呼び出してメッセージを処理するか、そうでなければ CCI_TIMEOUT と共に制御を戻すようにノードを構成するには、次のようにします。
If ( anything to do )
	CniDispatchThread;

   /* do the work */

	If ( work done O.K.)
		Return CCI_SUCCESS_CONTINUE;
	Else
		Return CCI_FAILURE_CONTINUE;
Else
  Return CCI_TIMEOUT;

デフォルトのメッセージ・パーサー属性のオーバーライド (オプション)

入力ノードは通常、 最初に入力メッセージを構文解析するメッセージ・パーサーを判別します。 例えば、MQInput ノードは、MQMD ヘッダーを構文解析するために MQMD パーサーが必要であることを指示します。 ユーザー定義入力ノードは、デフォルトとして組み込まれる、以下の属性を使用またはオーバーライドすることによって、適切なヘッダーかメッセージ・パーサー、および構文解析の制御のモードを選択することができます。

rootParserClassName
ユーザー定義入力ノードによってサポートされているメッセージ形式を構文解析するルート・パーサーの名前を定義します。 デフォルトでは GenericRoot に設定されます。 これは、ブローカーにパーサーを割り振らせたりチェーニングするために提供されているルート・パーサーです。 おそらく、ノードでこの属性値を変更する必要はありません。
firstParserClassName
ビット・ストリームを構文解析する役割を持つパーサーのチェーンの中で、 最初のパーサーの名前を定義します。 デフォルトでは XML に設定されます。
messageDomainProperty
入力メッセージを構文解析するのに必要なメッセージ・パーサーの名前を定義するオプションの属性。 サポートされる値は、MQInput ノードによってサポートされるものと同じです。 (詳しくは、MQInput ノードを参照してください。)
messageSetProperty
MRM パーサーが messageDomainProperty 属性によって指定された場合にのみ、 Message Set フィールドのメッセージ・セットの ID (またはメッセージ・セット名) を定義するオプションの属性。
messageTypeProperty
MRM パーサーが messageDomainProperty 属性によって指定された場合にのみ、 MessageType フィールドのメッセージの ID を定義するオプションの属性。
messageFormatProperty
MRM パーサーが messageDomainProperty 属性によって指定された場合にのみ、 Message Format フィールドのメッセージの形式を定義するオプションの属性。
常に既知の構造のデータで始まるユーザー定義の入力ノードを作成している場合は、 特定のパーサーがデータの開始を処理するようにすることができます。 例えば、MQInputWebSphere MQ キューからのみデータを読み取るので、このデータには常に先頭に MQMD が付いており、MQInput は firstParserClassName を MQHMD に設定しています。 ユーザー定義ノードが常に、特定のパーサー (例えば "MYPARSER") で構文解析できる構造で始まるデータを処理する場合は、以下の方法で firstParserClassName を MYPARSER に設定します。
  1. インプリメンテーション関数を宣言します。
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix bipGetMessageflowNodeFactory()
    {
      ....
      CciFactory*      factoryObject;
      ....
      factoryObject = cniCreateNodeFactory(0, (unsigned short *)constPluginNodeFactory);
      ...
      vftable.iFpCreateNodeContext = _createNodeContext;
      vftable.iFpSetAttribute      = _setAttribute;
      vftable.iFpGetAttribute      = _getAttribute;
      ...  
      cniDefineNodeClass(&rc, factoryObject, (CciChar*)constSwitchNode, &vftable);
      ...
      return(factoryObject);
    }
  2. cniCreateNodeContext インプリメンテーション関数で属性を設定します。
    CciContext* _createNodeContext(
      CciFactory* factoryObject,
      CciChar*    nodeName,
      CciNode*    nodeObject
    ){
      NODE_CONTEXT_ST* p;
      ...
    
        /* Allocate a pointer to the local context */
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
        /* Create attributes and set default values */
        {
          const CciChar* ucsAttrName  = CciString("firstParserClassName", BIP_DEF_COMP_CCSID);
          const CciChar* ucsAttrValue = CciString("MYPARSER", BIP_DEF_COMP_CCSID) ;
          insAttrTblEntry(p, (CciChar*)ucsAttrName, CNI_TYPE_INTEGER);
          /*see sample BipSampPluginNode.c for implementation of insAttrTblEntry*/
    
          _setAttribute(p, (CciChar*)ucsAttrName, (CciChar*)ucsAttrValue);
          free((void *)ucsAttrName) ;
          free((void *)ucsAttrValue) ;
        }
    上記のコード例では、insAttrTblEntry メソッドが呼び出されます。 このメソッドは、サンプル・ユーザー定義ノード SwitchNode および TransformNode で宣言されます。

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

メッセージ・フローが再デプロイされたり、 実行グループの処理が (mqsistop コマンドを使用して) 停止されたりすると、 ノードは破棄されます。 ノードが破棄されるとき、cniDeleteNodeContext 関数を呼び出して、使用されていたすべてのメモリーおよび保持されていたすべてのリソースを解放する必要があります。 以下に例を示します。

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

  return;
}
特記事項 | 商標 | ダウンロード | ライブラリー | サポート | フィードバック

Copyright IBM Corporation 1999, 2014Copyright IBM Corporation 1999, 2014.

        
        最終更新:
        
        最終更新: 2015-02-28 17:48:09


タスク・トピックタスク・トピック | バージョン 8.0.0.5 | as09960_