C로 입력 노드 작성

시작하기 전에

LIL(Loadable Implementation Library)는 C 노드(또는 구문 분석기)용 구현 모듈입니다. LIL은 DLL(Dynamic Link Library)로 구현되며 파일 확장자 .dll이 아닌 .lil을 가집니다.

개발자가 작성해야 하는 구현 함수는 C 노드 구현 함수에 나열되어 있습니다. 이 프로세스를 돕기 위해 WebSphere Message Broker가 제공하는 유틸리티 함수는 C 노드 유틸리티 함수에 나열되어 있습니다.

WebSphere Message Broker에서는 두 개의 샘플 사용자 정의 노드, 즉 SwitchNode 및 TransformNode의 소스를 제공합니다. 현재 상태에서 이 노드를 사용하거나 수정할 수 있습니다.

본 주제에서는 C를 사용하여 입력 노드를 작성하기 위해 수행할 단계를 설명합니다. 다음 단계에 대한 개요가 제공됩니다.
  1. 노드 선언 및 정의
  2. 노드의 인스턴스 작성
  3. 속성 설정
  4. 노드 기능 구현
  5. 디폴트 메시지 구문 분석기 속성 대체(선택사항)
  6. 노드의 인스턴스 삭제

노드 선언 및 정의

브로커에 사용자 정의 노드를 선언 및 정의하려면 초기화 함수인 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* destinationList,        
        CciMessage* exceptionList,          
        CciMessage* message
    ){          
      ...
        /* Get data from external source */
        return CCI_SUCCESS_CONTINUE;                                    
    }
    리턴 값은 정기적으로 브로커로 제어를 리턴하는 데 사용됩니다.

    사용자 정의 입력 노드가 포함된 메시지 플로우가 정상적으로 전개될 때, 노드로 전달된 각 메시지마다 노드의 cniRun 함수가 호출됩니다.

    C 사용자 정의 노드를 컴파일하는 데 필요한 최소 코드는 C 스켈레톤 코드를 참조하십시오.

노드의 인스턴스 작성

다음 프로시저는 노드를 인스턴스화하는 방법을 보여줍니다.

  1. 브로커가 함수 포인터 테이블을 수신할 때는 사용자 정의 노드의 각 인스턴스화마다 cniCreateNodeContext 함수를 호출합니다. 사용자 정의 노드를 사용하는 세 개의 메시지 플로우가 있을 경우, 각각에 대해 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 구현 함수 내에서 호출되어야 합니다. 예를 들면, 세 출력 터미널을 가진 입력 노드를 정의하는 코드는 다음과 같습니다.
       {
                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) ;
    }
변경 시작노드가 가질 수 있는 구성 속성의 수에는 한계가 없습니다. 그러나 플러그인 노드는 기본 구성 속성으로 이미 구현된 속성을 구현하지 않아야 합니다. 이 기본 속성은 다음과 같습니다.
  • 레이블
  • 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 노드에 대한 자세한 정보는 MQInput 노드를 참조하십시오.)
messageSetProperty
messageDomainProperty 속성으로 MRM 구문 분석기가 지정된 경우에만 메시지 세트 필드에 메시지 세트 ID 또는 메시지 세트 이름을 정의하는 선택적 속성입니다.
messageTypeProperty
messageDomainProperty 속성으로 MRM 구문 분석기가 지정된 경우에만 메시지 유형 필드에 메시지의 ID를 정의하는 선택적 속성입니다.
messageFormatProperty
messageDomainProperty 속성으로 MRM 구문 분석기가 지정된 경우에만 메시지 형식 필드에 메시지 형식을 정의하는 선택적 속성입니다.
항상 알려진 구조의 데이터로만 시작하는 사용자 정의 입력 노드를 작성한 경우, 특정 구문 분석기가 데이터 시작을 처리하도록 할 수 있습니다. 예를 들면, MQInputNode는 WebSphere MQ 큐에서만 데이터를 읽으므로 이 데이터의 시작 부분에는 항상 MQMD가 있으며 MQInputNode는 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, 2006 마지막 갱신 날짜: 2006/08/21
as09960_