C로 메시지 처리 또는 출력 노드 작성

시작하기 전에

WebSphere Message Broker에서는 두 개의 샘플 사용자 정의 노드, 즉 SwitchNode 및 TransformNode의 소스를 제공합니다. 현재 상태에서 이 노드를 사용하거나 수정할 수 있습니다. 또한, C로 작성된 메시지 처리 노드를 포함하여 사용자 정의 노드 사용을 보여주는 User-defined Extension 샘플을 볼 수 있습니다.

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

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

WebSphere Message Broker에서는 두 개의 샘플 사용자 정의 노드, 즉 SwitchNode 및 TransformNode의 소스를 제공합니다. 현재 상태에서 이 노드를 사용하거나 수정할 수 있습니다. 사용할 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 함수를 호출합니다. 사용자 정의 노드를 사용하는 세 개의 메시지 플로우가 있을 경우, 각각에 대해 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) ;
    }
변경 시작노드가 가질 수 있는 구성 속성의 수에는 한계가 없습니다. 그러나 플러그인 노드는 기본 구성 속성으로 이미 구현된 속성을 구현하지 않아야 합니다. 이 기본 속성은 다음과 같습니다.
  • 레이블
  • 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/21
as09980_