Creazione di un nodo di output o di elaborazione messaggi in C

Prima di iniziare

WebSphere Message Broker fornisce l'origine per due nodi definiti dall'utente di esempio denominati SwitchNode e TransformNode. E' possibile utilizzare tali nodi nel loro stato attuale oppure modificarli. Inoltre, è possibile visualizzare l'esempio di estensione definita dall'utente in cui viene dimostrato l'uso dei nodi definiti dall'utente, incluso un nodo di elaborazione messaggi scritto in C.

Una libreria di implementazione caricabile, o LIL (Loadable Implementation Library), è il modulo di implementazione di un nodo C (o programma di analisi). Una LIL è implementata come una DLL (Dynamic Link Library). Ha l'estensione del file .lil, non .dll.

Le funzioni di implementazione che devono essere scritte dallo sviluppatore sono riportate in Funzioni di implementazione del nodo in C. Le funzioni di utilità che sono fornite da WebSphere Message Broker per facilitare questa elaborazione sono riportate in Funzioni di utilità del nodo in C.

WebSphere Message Broker fornisce l'origine per due nodi definiti dall'utente di esempio denominati SwitchNode e TransformNode. E' possibile utilizzare tali nodi nel loro stato attuale oppure modificarli. E' possibile inoltre utilizzare l'esempio esempio Estensione definita dall'utente.

Concettualmente, un nodo di elaborazione messaggi viene utilizzato per elaborare un messaggio mentre un nodo di output viene utilizzato per eseguire l'output di un messaggio come un flusso di bit. Tuttavia, quando si codifica un nodo di elaborazione messaggi o un nodo di output, questi sono essenzialmente la stessa cosa. E' possibile eseguire l'elaborazione messaggi all'interno di un nodo di output e similmente è possibile eseguire l'output di un messaggio su un flusso di bit utilizzando un nodo di elaborazione messaggi. Per semplicità, questo argomento fa riferimento principalmente al nodo come un nodo di elaborazione messaggi, tuttavia, tratta la funzionalità di entrambi i tipi di nodo.

Dichiarazione e definizione del nodo

Per dichiarare e definire un nodo definito dall'utente al broker è necessario includere una funzione di inizializzazione, bipGetMessageflowNodeFactory nella LIL. I passi seguenti vengono eseguiti sul thread di configurazione e evidenziano il modo in cui il broker chiama la funzione di inizializzazione e come tale funzione dichiara e definisce il nodo definito dall'utente:

  1. La funzione di inizializzazione, bipGetMessageflowNodeFactory, viene richiamata dal broker dopo il caricamento e l'inizializzazione della LIL da parte del sistema operativo. Il broker richiama tale funzione per individuare l'operatività della LIL e come è possibile eseguirne la chiamata. Ad esempio:
    CciFactory LilFactoryExportPrefix * LilFactoryExportSuffix
    bipGetMessageflowNodeFactory()
  2. La funzione bipGetMessageflowNodeFactory deve poi richiamare la funzione di utilità cniCreateNodeFactory. Questa funzione trasferisce un nome di produttore (o nome di gruppo) per tutti i nodi supportati dalla LIL in uso. Il nome di produttore (o nome di gruppo) deve essere univoco nell'ambito di tutte le LIL nel broker.
  3. La LIL deve quindi richiamare la funzione di utilità cniDefineNodeClass per trasferire il nome univoco di ciascun nodo e una tabella di funzioni virtuale degli indirizzi delle funzioni di implementazione.
    Ad esempio, nel codice riportato di seguito viene dichiarato e definito un singolo nodo denominato MessageProcessingxNode:
    {
    CciFactory*     factoryObject;
    int                  rc = 0;
    	CciChar factoryName[] = L"MyNodeFactory";
    	CCI_EXCEPTION_ST exception_st;
    
    	/* Crea il produttore per questo nodo */
    	factoryObject = cniCreateNodeFactory(0, factoryName);
    if (factoryObject == CCI_NULL_ADDR) {
    		/* L'eventuale gestione errori locale può essere inserita qui */
    	}
    	else {
    		/* Definisce i nodi previsti da questo produttore */
    		static CNI_VFT vftable = {CNI_VFT_DEFAULT};
    
    	/* Imposta tabella funzioni con puntatori sulle funzioni di implementazione del nodo */
    	vftable.iFpCreateNodeContext = _createNodeContext;
    vftable.iFpDeleteNodeContext = _deleteNodeContext;
    vftable.iFpGetAttributeName2 = _getAttributeName2;
    vftable.iFpSetAttribute      = _setAttribute;
    vftable.iFpGetAttribute2     = _getAttribute2;
    	vftable.iFpEvaluate          = _evaluate;
    
    	cniDefineNodeClass(0, factoryObject, L"MessageProcessingxNode", &vftable);
    
    	}
    
    /* Restituisce l'indirizzo di questo oggetto produttore al broker */
    return(factoryObject);
    }

    Un nodo definito dall'utente si identifica in quanto fornisce la funzionalità di un nodo di output o di elaborazione messaggi implementando la funzione cniEvaluate. I nodi definiti dall'utente devono implementare una funzione di implementazione cniEvaluate o a cniRun, altrimenti il broker non carica il nodo definito dall'utente e la funzione di utilità cniDefineNodeClass ha esito negativo, restituendo CCI_MISSING_IMPL_FUNCTION.

    Quando un flusso di messaggi contenente un nodo di elaborazione messaggi definito dall'utente viene distribuito con esito positivo, viene richiamata la funzione cniEvaluate del nodo per ciascun messaggio trasmesso al nodo.

    I dati del flusso di messaggi, ovvero il messaggio, l'ambiente globale, l'ambiente locale e l'elenco di eccezioni, vengono ricevuti al terminale di input del nodo.

    Ad esempio:
    void cniEvaluate(                
      CciContext*  context,                
      CciMessage*   destinationList,        
      CciMessage*  exceptionList,          
      CciMessage* message                 
    ){                                    
      ...
    }
    In merito al codice minimo richiesto per la compilazione di un nodo definito dall'utente C, consultare Skeleton code C.

Creazione di un'istanza del nodo

La seguente procedura mostra come creare l'istanza del nodo

  1. Quando il broker riceve la tabella dei puntatori di funzione, richiama la funzione cniCreateNodeContext per ciascuna istanza creata del nodo definito dall'utente. Se si dispone di tre flussi di messaggi che utilizzano il nodo definito dall'utente, per ciascuno di questi, viene richiamata la funzione cniCreateNodeContext. Questa funzione assegna la memoria per la creazione dell'istanza del nodo definito dall'utente. Ad esempio:
    1. Viene richiamata la funzione utente cniCreateNodeContext:
      CciContext* _Switch_createNodeContext(
        CciFactory*  factoryObject,
        CciChar*     nodeName,
        CciNode*    nodeObject
      ){
        static char* functionName = (char *)"_Switch_createNodeContext()";
        NODE_CONTEXT_ST* p;
        CciChar          buffer[256];
      
    2. Assegnare un puntatore al contesto locale ed eliminare il contenuto nell'area del contesto:
        p = (NODE_CONTEXT_ST *)malloc(sizeof(NODE_CONTEXT_ST));
      
        if (p) {
           memset(p, 0, sizeof(NODE_CONTEXT_ST));
    3. Salvare il puntatore dell'oggetto nodo nel contesto:
         p->nodeObject = nodeObject;
    4. Salvare il nome del nodo:
       CciCharNCpy((CciChar*) &p->nodeName, nodeName, MAX_NODE_NAME_LEN);
    5. Restituzione del contesto del nodo:
      return (CciContext*) p;
  2. Il broker richiama le funzioni di utilità appropriate per individuare i terminali di input e output del nodo. Ad un nodo sono associati una serie di terminali di input e di output. All'interno della funzione utente cniCreateNodeContext, devono essere eseguite chiamate a cniCreateInputTerminal e cniCreateOutputTerminal per definire i terminali del nodo utente. Tali funzioni devono essere richiamate all'interno della funzione di implementazione cniCreateNodeContext. Ad esempio, per definire un nodo con un terminale di input e due terminali di output:
        {
          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) ;
        }
    In merito al codice minimo richiesto per la compilazione di un nodo definito dall'utente C, consultare Skeleton code C.

Impostazione degli attributi

Gli attributi vengono impostati ogni volta che viene avviato il broker oppure quando un flusso di messaggi viene ridistribuito con nuovi valori. Gli attributi vengono impostati dal broker richiamando il codice utente sul thread di configurazione. Il codice utente deve memorizzare tali attributi nella relativa area di contesto del nodo, in modo da utilizzarli successivamente per l'elaborazione dei messaggi.

Successivamente alla creazione dei terminali di input e output, il broker richiama la funzione cniSetAttribute per passare i valori per gli attributi configurati per questa creazione dell'istanza del nodo definito dall'utente. Ad esempio:
    {
      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) ;
    }
Inizio modificaNon esistono limiti relativi al numero di attributi di configurazione che un nodo può avere. Tuttavia, è necessario che un nodo plug-in non implementi un attributo già implementato come attributo di configurazione base. Gli attributi base sono:
  • label
  • userTraceLevel
  • traceLevel
  • userTraceFilter
  • traceFilter
Fine modifica

Implementazione della funzionalità del nodo

Quando il broker richiama un messaggio dalla coda e questo arriva nel terminale di input del nodo di output o di elaborazione messaggi definito dall'utente, il broker richiama la funzione di implementazione cniEvaluate. Questa funzione viene richiamata sul thread di elaborazione messaggi e deve decidere come procedere con il messaggio. Tale funzione potrebbe essere richiamata su più thread, specialmente se vengono utilizzate ulteriori istanze.

Eliminazione di un'istanza del nodo

Nel caso di un nodo cancellato, il broker richiama la funzione cniDeleteNodeContext. Tale funzione deve liberare tutte le risorse utilizzate dal nodo definito dall'utente. Ad esempio:

void _deleteNodeContext(
  CciContext* context
){
  static char* functionName = (char *)"_deleteNodeContext()";
  free ((void*) context);  return;
}
Informazioni particolari | Marchi | Download | Libreria | Supporto | Commenti
Copyright IBM Corporation 1999, 2006 Ultimo aggiornamento: ago 17, 2006
as09980_