Skip to content

Mapping Pipeline

The three-namespace problem

IBM MQ uses multiple naming conventions depending on the interface:

MQSC names (e.g. CURDEPTH, DEFPSIST)
Short, uppercase tokens used in MQSC commands and the REST API's runCommandJSON endpoint.
PCF names (e.g. CurrentQDepth, DefPersistence)
CamelCase names from the Programmable Command Formats. Not used directly by the library at runtime, but they formed the intermediate namespace during the original extraction process that bootstrapped the mapping tables.
Developer-friendly names (e.g. current_depth, default_persistence)
Human-readable names for use in application code.

The mapping pipeline translates between MQSC and developer-friendly names. PCF names were used as an intermediate reference during the original extraction process but do not appear at runtime.

Qualifier-based mapping

Mappings are organized by qualifier (e.g. queue, channel, qmgr), not by command. A single qualifier's mapping tables serve all commands that operate on that object type. For example, the queue qualifier covers DISPLAY QUEUE, DEFINE QLOCAL, DELETE QALIAS, and all other queue-related commands.

This design avoids duplicating mapping data across commands and reflects how MQSC attributes are shared across command verbs.

Request mapping flow

When mapping is enabled, request attributes are translated before sending to the MQ REST API:

  1. Key mapping: Each developer-friendly attribute name is looked up in the qualifier's request key map. If found, the key is replaced with the MQSC parameter name.

  2. Value mapping: For attributes with enumerated values, the qualifier's request value map translates developer-friendly values to MQSC values (e.g. "yes""YES").

  3. Key-value mapping: Some attributes require both key and value to change simultaneously. The request key-value map handles cases where a single attribute expands to a different MQSC key+value pair (e.g. channel_type="server_connection"CHLTYPE("SVRCONN")).

In Ruby, request mapping happens inside the private mqsc_command method before the payload is sent. The Mapping.map_request_attributes module method handles the translation:

# Internal flow (simplified)
mapped = Mapping.map_request_attributes(
  qualifier, attributes,
  strict: @mapping_strict, mapping_data: @mapping_data
)

Response mapping flow

Response attributes are translated after receiving the MQ REST response:

  1. Key mapping: Each MQSC parameter name from the response is looked up in the qualifier's response key map. If found, the key is replaced with the developer-friendly name.

  2. Value mapping: Enumerated MQSC values are translated to developer-friendly values via the response value map (e.g. "YES""yes").

Response parameter mapping

When the caller specifies response parameters (the list of attributes to return), those names are also mapped from developer-friendly names to MQSC before being sent in the request. This allows callers to request specific attributes using their preferred naming convention.

Response parameter macros (like CFCONLOS for channel status) are recognized and passed through without mapping.

WHERE keyword mapping

The where parameter on DISPLAY methods accepts a filter expression like "current_depth GT 100". The first token (the keyword) is mapped from the developer-friendly name to the MQSC name. The rest of the expression is passed through unchanged.

Response mapping happens after the HTTP response is parsed. The Mapping.map_response_list module method handles batch translation:

# Internal flow (simplified)
mapped = Mapping.map_response_list(
  qualifier, parameter_objects,
  strict: @mapping_strict, mapping_data: @mapping_data
)

Custom mapping overrides

The built-in mapping tables cover all standard MQSC attributes, but sites may use different naming conventions. The mapping overrides mechanism lets you layer sparse changes on top of the built-in data without replacing it.

How merging works

Overrides are merged at the key level within each sub-map. You only specify the entries you want to change. A single override entry doesn't affect the hundreds of other mappings.

When an override is applied:

  1. The built-in mapping data is deep-copied (the original is never mutated).
  2. The specified qualifier's sub-map is updated: the entry for the overridden key changes to the new value.
  3. All other entries in that sub-map (and all other sub-maps) remain unchanged.

Supported override keys

The top level of overrides accepts two keys:

  • commands: Override command-level metadata (e.g. which qualifier a command resolves to). Each command entry is shallow-merged.
  • qualifiers: Override qualifier mapping tables. Each qualifier supports five sub-maps:
  • request key map — developer-friendly → MQSC key mapping for requests
  • request value map — value translations for request attributes
  • request key-value map — combined key+value translations for requests
  • response key map — MQSC → developer-friendly key mapping for responses
  • response value map — value translations for response attributes

Adding new qualifiers

You can add mappings for qualifiers not yet covered by the built-in data by providing a complete qualifier entry in the overrides.

Validation

The override structure is validated at session construction time. Invalid shapes raise errors immediately, so problems are caught before any commands are sent.

Opting out

Mapping can be disabled entirely or selectively:

  • Session-level: Disable mapping when creating the session.
  • Per-call: Disable mapping for a single command invocation.

When mapping is disabled, attributes pass through in their native MQSC form.

In Ruby, overrides are passed when creating the session:

overrides = {
  'qualifiers' => {
    'queue' => {
      'response_key_map' => {
        'CURDEPTH' => 'queue_depth'
      }
    }
  }
}

session = MQ::REST::Admin::Session.new(
  'https://localhost:9443/ibmmq/rest/v2', 'QM1',
  credentials: MQ::REST::Admin::BasicAuth.new(username: 'admin', password: 'admin'),
  mapping_overrides: overrides,
  mapping_overrides_mode: :merge  # or :replace
)

Strict vs lenient mode

Strict mode (default): Any attribute name or value that cannot be mapped raises an error. This catches typos and unsupported attributes early.

Lenient mode: Unknown attribute names and values pass through unchanged. This is useful when working with attributes not yet covered by the mapping tables.

The mode is set at session creation and applies to all mapping operations.

Qualifier resolution

When a command is executed, the mapping qualifier is resolved by:

  1. Looking up the command key (e.g. "DISPLAY QUEUE") in the command metadata for an explicit qualifier.
  2. Falling back to a default map (e.g. QLOCALqueue, CHANNELchannel).
  3. As a last resort, lowercasing the MQSC qualifier.

This means DEFINE QLOCAL, DEFINE QREMOTE, and DISPLAY QUEUE all resolve to the queue qualifier and share the same mapping tables.

In Ruby, strict mode raises MappingError with an issues attribute containing an array of MappingIssue objects:

begin
  session.display_queue(name: 'MY.QUEUE', unknown_attr: 'value')
rescue MQ::REST::Admin::MappingError => e
  e.issues.each do |issue|
    puts "#{issue.direction}: #{issue.reason} for #{issue.attribute_name}"
  end
end