3-CML - Console Markup Language

This document describes a way of managing AMQP servers from a remote client application, using a transport mechanism built over AMQP, and an XML language used to exchange information between a management component built-in to the server, and a management application.

  • Name: gro.pqma.ikiw|SMC-3#gro.pqma.ikiw|SMC-3
  • Editor: Pieter Hintjens <moc.xitami|hp#moc.xitami|hp>
  • Contributors: none
  • State: stable


Copyright (c) 2008 iMatix Corporation.

This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

This Specification is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses>.

Change Process

This document is governed by the gro.pqma.ikiw|SSOC-1#gro.pqma.ikiw|SSOC-1 specification.



We define a standard language (Console Markup Language, or CML) and transport mechanism for the remote administration of AMQP servers. CML is a simple XML language for representing server-side entities, their properties, and possible actions. Further, CML defines semantics for actions to be taken on objects. CML is transported on top of AMQP using basic AMQP routing and queueing functionality.


A 'console' is a remote application that monitors, configures, and manages one or more servers. CML is designed to allow remote configuration, control and management of an AMQP server, including:

  • Server configuration.
  • Security configuration (authentication and access controls).
  • Monitoring of key entities (queues, etc.)
  • Collection of status information (performance, statistics)
  • Administrative actions (purge queue, disconnect connection, etc.)

We want the console to be able to have these features:

  • To be rapid, even when many people are operating (different parts of) an AMQP server. The speed of reaction of the console is an important part of its functionality.
  • To be portable to any desired user interface technology, including web, command-line, JMX, etc. Ideally, end-users should be able to make customised operator interfaces, scripts, etc. We want the console to be user-extensible.
  • To be generally compatible with conventional console abstractions, e.g. Java management beans.
  • To provide access to all "operable" internals of the server, i.e. to any object that may be tuned, configured, or managed.
  • To hide all aspects of the server that are not "operable", i.e. any object that should not be touched or seen. The operator must not be able to cause harm by misuse of the console.
  • To have no significant impact on server performance or stability even when heavily used. The console must be non-intrusive, and wholly safe.
  • Eventually, to be transactional, so that operations are completed fully, or not at all.
  • Lastly, to be self-describing, using data schemas that clients can refer to, adapting statically or dynamically as suitable.

General console architecture

Server and client Layers

The console is built using the AMQP protocol. That is, the server does not export any user interface, but rather an API on top of which arbitrary user interfaces can be built. The simplest architecture is this:

AMQP Server              GUI or cmdline
.-----------.             .-----------.
|           |             |           |
|  Console  | <==AMQP==>  |  Console  |
|  Server   |             |  Client   |
|           |             |           |
`-----------'             `-----------'

Where the console client is responsible for the user interface - command line or GUI. A more sophisticated architecture uses a console standard such as JMX so that it is easy to write arbitrary operator applications:

AMQP Server                 Proxy               GUI or cmdline
.-----------.             .-----------.           .----------.
|           |             |           |           |          |
|  Console  | <==AMQP==>  |  Console  | <==JMX==> | Operator |
|  Server   |             |  Client   |           |   Appl   |
|           |             |           |           |          |
`-----------'             `-----------'           `----------'
  • The console consists of a server component and a client component.
  • The console server is an application that is embedded into the AMQ server.
  • The console client is an application written in an arbitrary language.
  • The console client and server communicate using AMQP.

The server schema

We specify formally that:

  • The console works on a set of entity definitions we call "classes", and a set of live entities we call "objects".
  • The collection of classes that the server supports is its "schema".
  • Schemas are given globally-unique names and versions.

Every AMQP server can implement its own schema, depending on its specific functionality. We do not assume that all console clients know all schemas in advance.

This is an example of a schema structure:

 :-- vhost
 :    :
 :    :-- exchange
 :    :
 :    `-- queue
 :        :
 :        `-- consumer
 `-- connection

Classes, fields, and methods

The schema is an arbitrarily-complex hierarchical structure representing the classes of entities in the server.

An object class is defined as follows:

  • The class has a name, e.g. "server", unique within the schema.
  • Each object instance has a numeric identifier.
  • The class is composed of zero or more data fields (the object's properties).
  • The class may allow one or more methods.

A data field is defined as follows:

  • The field has a name.
  • The field has a data type.
  • The field may be restricted to a set of named values.
  • The field has a label, used to construct a user interface.
  • The field has a description, used to construct a user interface.
  • The field is marked as readable and/or writeable.
  • The field may contain one or more child fields.

Methods accept a number of arguments and perform some action on an object, and return a status value. A method is defined as follows:

  • The method has an internal name.
  • The method has a label, used to construct a user interface.
  • The method carries zero or more data fields (the method's arguments).
  • The method has a description, used to construct a user interface.


The API consists of these commands:

  • "schema-request" - requests the server schema.
  • "schema-reply" - returns the server schema.
  • "inspect-request" - requests the properties of a specific object.
  • "inspect-reply" - returns the properties of a specific object.
  • "modify-request" - requests changes to a specific object.
  • "modify-reply" - confirms changes to a specific object.
  • "method-request" - executes a method on a specific object.
  • "method-reply" - returns result of a method-request.
  • "notify" - (from server to client) send a notification.

Object identification

Each object has a unique 64-bit identifier assigned by the server when it creates the object. This identifier is used in all messages when referring to an object.

ID 0 (zero) always represents the root object.

The console API


The 'console API' is a remote API that lets an application query and manipulate entities on the server. The API consists of a set of commands passed between the client (console) and the server.

General design

The console API consists of two pieces:

  • Execute a command on a given object. This consists of a request from the client to the server, and a reply back from the server to the client.
  • Get a notification from the server. Notifications are sent asynchronously using the AMQP topic routing mechanisms.

The console API consist of Basic content messages, exchanged using these AMQP methods:

  • Basic.Publish
  • Basic.Consume and Basic.Deliver
  • Basic.Browse and Basic.Browse-Ok / Browse-Empty.

The request-reply mechanism uses standard queues. The client creates a temporary, private queue and binds this to amq.direct using the queue name as routing key. It then sends CML commands to the amq.system exchange, specifying "amq.console" as the routing key, and its queue name as the reply-to field. To match up responses with requests, it can set the message-id in requests - the Console will use the same value in responses.

Every request generates a response, on the condition that the reply-to field correctly refers to a queue.

We can show the client's request-reply logic using PAL scripting:

  • The client creates a temporary, private reply queue and binds this to the amq.direct exchange:
<queue_declare queue = "" />
    queue = "$queue"
    exchange = "amq.direct"
    routing_key = "$queue" />
  • The client formats a request (in this case we read a test CML message from a text file):
    read = "console.txt"
    reply_to = "$queue"
    message_id = "id-001" />
  • The client publishes the request to the amq.system exchange:
    exchange = "amq.system"
    routing_key = "amq.console" />
  • The client waits for a response on its queue:
<basic_consume queue = "$queue" />
<wait />
    <echo>Response arrived from console</echo>

The notification mechanism uses topic routing and subscription queues. The client creates a temporary, private queue and binds this to the amq.notify exchange (a topic exchange), with a routing key that specifies which notifications it wants to receive.

We can show the client's notification logic using PAL scripting:

  • The client creates a temporary, private reply queue and binds this to the amq.notify exchange:
<queue_declare queue = "" />
<queue_bind queue = "$queue" exchange = "amq.notify" routing_key = "amq.*" />
  • The client defines a consumer on the queue:
<basic_consume queue = "$queue" />
  • The client waits for notifications on its queue:
        <echo>Response arrived from console</echo>

Console message language

All messages between the console client and the server are formatted using an XML language we call "CML", the Console Message Language. CML uses a minimalistic XML syntax - no stylesheets, namespaces, document types, etc.

Here are some examples of CML:

<cml version = "1.0">
    <schema-request />
<cml version = "1.0">
    <inspect-request object = "0" />
<cml version = "1.0">
    <modify-request object = "0">
        <field name = "active">0</field>

CML has a grammar that covers all possible server schemas. This is the overall grammar for CML messages:

cml             = <cml version = "1.0">
                     client-message | server-message

This is the grammar for client messages:

cml             = schema-request
                | inspect-request
                | modify-request
                | method-request
schema-request  = <schema-request />
inspect-request = <inspect-request object = "object-id" />
object-id       = 0..maxlongint-1
modify-request  = <modify-request object = "object-id">
                    [ field-data ] ...
field-data      = <field name = "field-name">field-value</field>
field-name      = valid-name
valid-name      = {A-Za-z0-9-_.}...
field-value     = string representation of field value
method-request  = <method-request object = "object-id" name = "method-name">
                    [ field-data ] ...
method-name     = valid-name

This is the grammar for server messages:

cml-command     = schema-reply
                | inspect-reply
                | modify-reply
                | method-reply
                | invalid
                | notify
schema-reply    = <schema-reply name = "schema-name" version = "schema-version"
                    status = "reply-status" >
                   [ schema-class ]...
schema-name     = valid-name
schame-version  = valid-name
reply-status    = ok | notfound | noaccess | invalid
schema-class    = <class name = "class-name" label = "class-label">
                   [ schema-field ]...
                   [ schema-method ]...
class-name      = valid-name
class-label     = valid-text
valid-text      = {printable}...
schema-field    = group-field | simple-field
group-field     = <group name = "field-name"
                   [ inspect = "inspect-flag" ] [ modify = "modify-flag" ]
                   [ label = "field-label" ] >
                   [ field-text ]
                   [ schema-field ]...
inspect-flag    = 0 | (1)
modify-flag     = (0) | 1
field-label     = valid-text
field-text      = valid-text
simple-field    = <field name = "field-name"
                   [ type = "field-type" ] [ repeat = "repeat-flag" ]
                   [ inspect = "inspect-flag" ] [ modify = "modify-flag" ]
                   [ label = "field-label" ] >
                   [ field-text ]
                   [ enum-value ] ...
field-type      = string | int | bool | time | objref
repeat-flag     = (0) | 1
enum-value      = <value name = "value-name">field-value</value>
value-name      = valid-text
schema-method   = <method name = "method-name" label = "method-label">
                   [ schema-field ]...
method-label    = valid-text
inspect-reply   = <inspect-reply class = "class-name" object = "object-id"
                     status   = "reply-status"
                   [ notice = "notice-text" ] >
                    [ field-data ]...
modify-reply    = <modify-reply
                     class = "class-name"
                     object = "object-id"
                     status = "reply-status"
                   [ notice = "notice-text" ] />
notice          = valid-text
method-reply    = <method-reply
                     class = "class-name"
                     object = "object-id"
                     status = "reply-status"
                   [ notice = "notice-text" ] />
invalid         = <invalid />
notify          = <notify>

Field types

The goal of defining fields is to allow the automatic production of user interface forms without too much work. We allow these types of field:

  • string: defines a string field. The maximum value of a string field is 255 octets when an object is modified, and no limit on output. This is the default type.
  • int: defines an integer. Integers are unsigned 32 bits.
  • bool: defines a boolean value, which can be shown as a check box.
  • time: defines a date/time, held as a UTC time_t format.
  • object: defines a relationship to another object.

String and integer fields can be enumerated, with one or more values. These would show as radio options (for 3-4 or fewer fields) or select boxes (for 5 or more options), e.g.:

<field name = "status" type = "int" label = "Operational status">
    <value name = "not ready"    >0</value>
    <value name = "active"       >1</value>
    <value name = "shutting down">2</value>

This is a minimalistic typing model that we will most likely refine over time, e.g. defining visible and internal size limits for strings and integers, and allowing multiline text fields.

Object names

All objects must have a field called "name" that specifies a unique name for the object within the current set of objects of a particular type.

The 'schema' command

The 'schema' commmand asks the server for the server schema. Any AMQP server implements exactly one schema. Schemas are named and versioned so that clients can either download schemas fully dynamically, or work with in-built schemas and verify that their servers are compatible.

An example of the schema command:

C: <cml version = "1.0">
      <schema-request />
S: <cml version = "1.0">
      <schema-reply name = "www.openamq.org/kernel" version = "0.1" status = "ok">
         <class name = "server">
            <field name = "ip-address" label = "Server IP address" />
            <field name = "port"       label = "Port for connections" />
            <field name = "version"    label = "Server software version" />
            <field name = "platform"   label = "Server platform" />
         <class name = "vhost">
         <class name = "connection">

The reply-status field defines whether the command was successful or not. This field has these possible values:

  • 'ok' means the command completed successfully.
  • 'notfound' means the specified class (or object, for other commands) did not exist.
  • 'noaccess' means the client application was not allowed to execute the command.
  • 'invalid' means the command was wrongly formatted or incorrect.

The 'inspect' command

The 'inspect' command asks the server for a specific object. The command takes an object ID as argument, and returns all readable fields for the object, with optionally a list of all child objects.

The top-level object always has an ID zero, so the client will inspect this object first, in order to navigate the object tree.

For example:

C: <cml version = "1.0">
      <inspect-request object = "0" />
S: <cml version = "1.0">
      <inspect-reply class = "broker" object = "0" status = "ok">
         <field name = "ip-address"></field>
         <field name = "port">5672</field>
         <field name = "version">0.9c2</field>
         <field name = "platform">Linux</field>
         <field name = "exchange" id = "1" />
         <field name = "exchange" id = "2" />

The 'modify' command

The 'modify' command asks the server to set certain fields of an object. These must be fields with the "modify" attribute set to 1 in the schema. For example:

C: <cml version = "1.0">
      <modify-request object = "2">
         <field name = "enabled">0</field>
S: <cml version = "1.0">
      <modify-reply object = "2" status = "ok" />

If the client specifies fields that are not valid (not in the modify view), the server will respond with an "invalid" status.

The 'method' command

The 'method' command provides a set of fields and a method name and asks the server to execute that method. Methods do not return values except a status code. For example:

C: <cml version = "1.0">
      <method-request name = "purge" object = "32" />
S: <cml version = "1.0">
      <method-reply name = "purge" object = "32" status = "ok" />

If the client specifies fields that are not valid (not in the modify view), the server will respond with an "invalid" status.

The 'notify' command

The server broadcasts informational, warning and error messages using 'notify' commands. Any correctly subscribed AMQP client can get these notifications.

The notification consists of a textual message:

S: <cml version = "1.0">
        E: queue exceeded configured limit of 5000.


Add a New Comment

Edit | Files | Tags | Source | Print | Talk

Use one of these tags to define the specification's state:

  • raw - new specification
  • draft - has at least one implementation.
  • stable - has been deployed to real users.
  • legacy - is being replaced by newer specifications.
  • retired - has been replaced and is no longer used.
  • deleted - abandoned before becoming stable.