WebSphere Message Brokers
File: as24980_
Writer: Lorraine Waitt

Task topic

This build: July 31, 2007 21:38:46

Extending the capability of a C parser

Before you start

Ensure that you have read and understood the following topic:

Implementing the parser functionality

A parser needs to implement the following types of implementation function:
  1. input functions
  2. parse functions
  3. output functions

Each type of function is described below.

Implementing input functions

There are three input functions: Your parser must implement one, and only one, of these input functions.

The broker will invoke the input function when your user-defined parser is required to parse an input message. The parser must tell the broker how much of the input bitstream buffer that it claims to own. In the case of a fixed-size header, the parser claims the size of the header. If the parser is intended to handle the whole message, it claims the remainder of the buffer.

For example:
  1. The broker invokes the cpiParseBufferEncoded input function:
    int cpiParseBufferEncoded(
      CciParser*  parser,
      CciContext* context,
      int         encoding,
      int         ccsid
    ){
      PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
      int                rc;
    
  2. Get a pointer to the message buffer, then set the offset using the cpiBufferPointer utility function:
      pc->iBuffer = (void *)cpiBufferPointer(&rc, parser);
      pc->iIndex = 0;
  3. Save the format of the buffer:
      pc->iEncoding = encoding;
      pc->iCcsid = ccsid;
  4. Save the size of the buffer using the cpiBufferSize utility function:
      pc->iSize = cpiBufferSize(&rc, parser);
  5. Prime the first byte in the stream using the cpiBufferByte utility function:
      pc->iCurrentCharacter = cpiBufferByte(&rc, parser, pc->iIndex);
  6. Set the current element to the root element using the cpiRootElement utility function:
      pc->iCurrentElement = cpiRootElement(&rc, parser);
  7. Reset the flag to ensure parsing is reset correctly:
      pc->iInTag = 0;
    
  8. Claim ownership of the remainder of the buffer:
      return(pc->iSize);
    }

Implementing parse functions

General parse functions (for example, cpiParseFirstChild) are those invoked by the broker when the syntax element tree needs to be created in order to evaluate an ESQL or Java expression. For example, a filter node uses an ESQL field reference in an ESQL expression. This field reference must be resolved in order to evaluate the expression. Your parser's general parse function is called, perhaps repeatedly, until the requested element is either created or is known by the parser to not exist.

For example:
void cpiParseFirstChild(
  CciParser*  parser,
  CciContext* context,
  CciElement* element
){
  PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
  int                rc;

  if ((!cpiElementCompleteNext(&rc, element)) &&
      (cpiElementType(&rc, element) == CCI_ELEMENT_TYPE_NAME)) {

    while ((!cpiElementCompleteNext(&rc, element))     &&
           (!cpiFirstChild(&rc, element)) &&
           (pc->iCurrentElement))
    {
      pc->iCurrentElement = parseNextItem(parser, context, pc->iCurrentElement);
    }
  }
  return;
}

Implementing output functions

There are three output functions: Your parser must implement one, and only one, of these output functions.

The broker will invoke the output function when your user-defined parser is required to serialize a syntax element tree to an output bit stream. For example, a Compute node might have created a tree in the domain of your user-defined parser. When this tree needs to be output by, for example, an MQOutput node, the parser is responsible for appending the output bitstream buffer with data that represents the tree that has been built.

For example:
int cpiWriteBufferEncoded(
  CciParser*  parser,
  CciContext* context,
  int         encoding,
  int         ccsid
){
  PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
  int                initialSize = 0;
  int                rc = 0;
  const void* a;
  CciByte b;

  initialSize = cpiBufferSize(&rc, parser);
  a = cpiBufferPointer(&rc, parser);
  b = cpiBufferByte(&rc, parser, 0);

  cpiAppendToBuffer(&rc, parser, (char *)"Some test data", 14);

  return cpiBufferSize(0, parser) - initialSize;
}

Implementing a message header parser

Normally, the incoming message data is of a single message format, so one parser is responsible for parsing the entire contents of the message. The class name of the parser that is needed is defined in the Format field in the MQMD or the MQRFH2 header of the input message.

However, the message might consist of multiple formats, for example where there is a header in one format followed by data in another format. In this case, the first parser has to identify the class name of the parser that is responsible for the next format in the chain, and so on. In a user-defined parser, the implementation function cpiNextParserClassName is invoked by the broker when it needs to navigate down a chain of parser classes for a message comprising multiple message formats.

If your user-defined parser supports parsing a message format that is part of a multiple message format, the user-defined parser must implement the cpiNextParserClassName function.

For example:
  1. Call the cpiNextParserClassName function:
    void cpiNextParserClassName(
      CciParser*  parser,
      CciContext* context,
      CciChar*    buffer,
      int         size
    ){
      PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
      int                rc = 0;
    
  2. Copy the name of the next parser class to the broker:
      CciCharNCpy(buffer, pc->iNextParserClassName, size);
    
      return;
    }
Notices | Trademarks | Downloads | Library | Support | Feedback

Copyright IBM Corporation 1999, 2007Copyright IBM Corporation 1999, 2007. All Rights Reserved.
This build: July 31, 2007 21:38:46

as24980_ This topic's URL is: