使用 C 语言创建消息处理或输出节点

开始之前

WebSphere Message Broker 为称为 SwitchNode 和 TransformNode 的两个用户定义的样本节点提供了数据源。您可以使用当前状态下的这些节点,也可以修改这些节点。另外您还可以查看用户定义的扩展样本,该样本将展示如何使用包括用 C 语言编写的消息处理节点在内的用户定义节点。

可装入实现库或 LIL 是 C 节点(或解析器)的实现模块。LIL 实现为动态链接库(DLL)。它的文件扩展名为 .lil,而不是 .dll。

必须由开发者写的实施函数在C 节点实施函数中列出。WebSphere Message Broker 提供的用于帮助此过程的实用程序函数在C 节点实用程序函数中列出。

WebSphere Message Broker 为称为 SwitchNode 和 TransformNode 的两个用户定义的样本节点提供了数据源。您可以使用当前状态下的这些节点,也可以修改这些节点。您还可以使用用户定义的扩展样本样本。

在概念上,消息处理节点用于按相同方法处理消息,输出节点用于将消息输出为位流。但是,当您编码消息处理节点或输出节点时,它们本质上是相同的东西。您可以在输出节点中执行消息处理,同样您可以使用消息处理节点将消息输出到位流。为简便起见,本主题在提到节点时大都指的是消息处理节点,不过本主题依然会讲述这两类节点的功能。

本主题中涉及了这两种类型节点的功能。它概述了下列步骤:
  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 函数提供消息处理或输出节点来标识它自己。用户定义的节点必须实现 cniEvaluatecniRun 实施函数,否则代理将不会装入用户定义的节点,cniDefineNodeClass 实用程序函数将失败并返回 CCI_MISSING_IMPL_FUNCTION。

    当包含用户定义的消息处理节点的消息流成功部署后,为传到节点的每条消息调用节点的 cniEvaluate 函数。

    消息流数据在节点的输入终端(即,消息、全局环境、本地环境和异常列表)接收。

    例如:
    void cniEvaluate(                
        CciContext* context,                
        CciMessage* destinationList,        
        CciMessage* exceptionList,          
        CciMessage* message                 
    ){                                    
      ...
    }
    有关编译 C 用户定义的节点所需的最少代码,请参阅C 框架代码

创建节点的实例

下列过程向您显示了如何实例化您的节点:

  1. 当代理接收到函数指针的表,它为每个用户定义的节点的实例化调用函数 cniCreateNodeContext。如果您有三个使用您的用户定义的节点的消息流,将为每个消息流调用您的 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 中,还可以调用 cniCreateInputTerminalcniCreateOutputTerminal 来定义用户节点终端。这些函数必须在 cniCreateNodeContext 实施函数中调用。例如,要定义带有一个输入终端和两个输出终端的节点:
        {
                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 最后一次更新时间:2006/08/14
as09980_