RestMS - RESTful Messaging Service

This document describes RestMS, a RESTful Messaging Service that exposes AMQP networks via a pure HTTP interface. RestMS is designed to interoperate with AMQP/0.9.1 and future versions of AMQP.

  • Name: gro.pqma.ikiw|SMTSER-7#gro.pqma.ikiw|SMTSER-7
  • Editor: Pieter Hintjens <moc.xitami|hp#moc.xitami|hp>
  • Resources: http://www.restms.org.

License

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.

Goals

RestMS aims to:

  • Deliver AMQP-interoperable enterprise messaging to web applications.
  • Deliver the scalability and simplicity of the RESTful model.
  • Be easy to use in any programming language, for any application, on any platform.
  • Define a standardized and implementation-independent URI mapping scheme.

This specification is an initial, simple RESTful mapping of AMQP. It does not claim to be complete, robust, or fast. Our intention is to demonstrate that RESTful messaging is feasible today, and that the needs of a RESTful messaging service as a set of clean, idempotent URL methods, are a constructive input into the design of AMQP/1.0.

Introduction

"All REST interactions are stateless. That is, each request contains all of the information necessary for a connector to understand the request, independent of any requests that may have preceded it." — Roy Fielding

RestMS is a RESTful messaging service designed for web applications. A RestMS application can be as simple as this fully working "Hello World!" example in Perl:

#!/usr/bin/perl
#   Hello World application for RestMS
#
use LWP::UserAgent;
use HTTP::Request::Common;

my $hostname = $ARGV [0]? $ARGV [0]: "localhost";
my $base = "http://$hostname/restms";
my $ua = new LWP::UserAgent;
$ua->agent ('Perl');
$ua->credentials ($hostname, "RestMS", "guest", "guest");

#   In one step, create a pipe named 'world', create a fanout feed named
#   'ping', and create a join on all messages, using address string 'hello':
my $response = $ua->request (PUT "$base/pipe/world/hello\@ping/fanout");
$response->code == 200 || die;

my $response = $ua->request (POST "$base/hello\@ping", 
    Content => "Hello World!\n");
$response->code == 200 || die;

#   Message goes into feed and then comes back to our pipe
my $response = $ua->request (GET "$base/pipe/world/");
$response->code == 200 || die;
print $response->content;

RestMS uses URIs to address a set of resources. Applications create, use, and delete these resources. RestMS URIs are standard HTTP URIs, and RestMS is designed to be built into a web server as an extension or URI handler. By convention, as shown in our hello world example and this documentation, URI paths start with "/restms".

Resource hierarchy

RestMS uses a simple loosely-coupled message model based on these main types of resource:

  • A "feed" is a named stream of messages that is filled at one end by publishing applications, and used at the other end by subscriber applications.
  • A "pipe" is a named stream of messages that is filled from a feed, and made available to applications.
  • An "address" is where applications send messages to. Addresses are contained within feeds, and applications can invent addresses arbitrarily.
  • A "join" regulates the flow of messages from a feed into a pipe. A join says, "route all messages that match this set of addresses, from this feed, into this pipe".
  • A "nozzle" regulates the flow of messages from a pipe to an application. A nozzle holds a series of messages delivered to one application. Nozzles let multiple applications share a single pipe safely.

These resources form a hierarchy:

restms
    pipe_class
        pipe
            join
            nozzle
                message
    feed_class
        feed

AMQP architects may recognize the similarity with AMQP concepts but the RestMS resources are overall simpler and more regular than the AMQP ones.

Like AMQP, RestMS keeps applications at a proper distance from each other. Publishers do not send to recipients but to addresses, and recipients can freely choose which addresses they accept. An architecture where pieces have explicit knowledge of each other is fragile and expensive to change. The loosely-coupled model allows consumers and publishers to join and leave the network freely, and supports robust designs such as redundancy, workload distribution, and dynamic service registration and access.

Publishing applications write a message to an address within a feed, which causes the message to be placed in the feed and made available to consuming applications. Consuming applications create a pipe, join the pipe to selected addresses within one or more feeds, and then read the messages that come down their pipe, through one or more nozzles.

Both feeds and pipes acts like first-in-first-out queues, but they do different types of work. Feeds are mainly concerned with storing and forwarding messages to multiple pipes, while pipes are mainly concerned with supplying messages to a single application. In a distributed network, feeds will be close to publishers, and pipes will be close to subscribers. Feeds are public resources, pipes are usually private to one or a few applications. Feeds can have sophisticated semantics for deciding what messages go where, while pipes do not.

RestMS is an evolution of AMQP

While RestMS remains interoperable with existing AMQP networks (via AMQP servers that implement the RestMS extension class), it is intended to be both simpler to understand and use, and more in line with the evolution of AMQP towards an AMQP/1.0 specification.

RestMS deliberately invents new nomenclature but for those familiar with AMQP, a feed corresponds to an exchange and/or shared queue, an address corresponds to a routing key, a pipe is analogous to a private queue, and a join matches an AMQP binding. If it helps to understand RestMS, these are the main shifts that RestMS makes from the AMQP/0.9.1 semantic model:

  • Shared queues are merged into exchanges, and the resulting entity is renamed "feed". In AMQP, exchanges have no state, while shared queues cannot do routing. In RestMS, feeds have both state and capacity to route messages.
  • The exclusive queue concept are renamed to "pipe" and moved closer to the client edge.
  • The consumer and transaction concepts are merged, renamed to "nozzle", and moved to the client edge.
  • The binding / routing key concepts are merged into a new concept called "address", which is used both for publishing messages and for joining pipes to feeds.

The main semantic change from AMQP to RestMS is that we do not allow loose coupling of shared queues, i.e. the ability to bind and address a shared queue using arbitrary routing keys. We consider this AMQP functionality to be confusing and not needed by any common messaging scenarios. In RestMS, shared queues are addressed directly, as named feeds. This simplification is a key part of RestMS's overall design.

Implementation architecture

The RestMS software architecture consists of these components:

  • A RestMS server, which speaks HTTP or HTTPS at one side, and one or more messaging protocols (such as AMQP) at the other.
  • A set of RestMS client applications, which use the HTTP protocol to execute RestMS methods, and thus to send and receive messages.
  • One or more messaging infrastructures, for example an AMQP server connected to a set of AMQP client applications. This infrastructure is invisible to the RestMS clients, except insofar as it exists as a sink for and a source of interesting messages.

In this document we provide a formal specification for the syntax and semantics of the HTTP conversation carried out between RestMS clients and the RestMS server, with the goal of explaining to developers how to write RestMS client applications, and to implementors how to build conforming RestMS server implementations.

MIME types, responses, and caching

RestMS returns three types of content:

  1. Success responses to RestMS methods, which are formatted as structured data.
  2. Failure responses to RestMS methods, which are formatted as HTML data with content type "text/html".
  3. Message deliveries from GET methods on nozzles, which are formatted as binary data with content type "application/octet-stream".

We plan to add a multipart chunked encoding for stream pipes.

Structured success responses are formatted either in XML or in JSON, depending on the Accept: header. The server will parse the Accept: header and look for the first instance of any of:

  • "application/xml" - format the response as XML
  • "text/xml" - format the response as XML
  • "application/json" - format the response as JSON

The response MIME type matches that used from the Accept: header.

XML response messages use this XML format, which matches the resource hierarchy except that pipe classes are not browsable, since pipes are private resources:

<?xml version="1.0"?>
<restms version="1.0" status="ok">
    <pipe_class name="name" uri="uri" size="pipes" />
    <feed_class name="name" uri="uri">
        <feed name="name" uri="uri" />
    </feed_class>
    <pipe name="name" uri="uri" size="messages">
        <join address="pattern" feed="name" uri="uri" />
        <nozzle name="name" size="messages" />
    </pipe>
    <feed name="name" uri="uri" />
</restms>

All items except the root can occur 0 or more times. JSON response messages use a corresponding JSON format, where all items except the root item can also occur 0 or more times:

{
"restms":{ "version":"1.0", "status":"ok",
    "pipe_class":[ { "name":"name", "uri":"uri", "size":pipes } ],
    "feed_class":[ { "name":"name", "uri":"uri",
        "feed":[ { "name":"name", "uri":"uri" } ]
        } ],
    "pipe":[ { "name":"name", "uri":"uri", "size":messages,
        "join":[ { "address":"pattern", "feed":"name", "uri":"uri" } ],
        "nozzle":[ { "name":"name", "size":messages } ]
        } ],
    "feed":[ { "name":"name", "uri":"uri" } ]
    }
}

The actual response content for each method depends on the work done by the method, and we do not specify the responses formally here, yet.

Content returned by a RestMS implementation is never cached. That is, the response headers are set as follows:

  • Cache-control: no-cache
  • Expires: 0
  • Last-modified: empty

Topology

RestMS is based on a hypermedia dialog between a client application and a server. In other words, applications use URIs to work with resources, and RestMS responses contain URIs to further resources when appropriate.

The root resource is called the "topology". Applications get a map of the implementation by querying this topology. The URI for the topology is "/restms" with no further path information:

/restms

The topology allows one method, "GET".

Feeds

Feeds are named entities that are contained within feed classes. The URI for a feed consists of a feed class followed by a feed name:

/restms/{feed-class}/{feed-name}

The set of valid feed classes, and their meaning, is defined by the server implementation. Each feed class defines a particular set of semantics for the feeds it contains. Applications can create and delete feeds at runtime. RestMS server implementations can also offer predefined feeds. Applications which create, query, or delete feeds need to know their class. Applications that publish messages to feeds, or take messages off feeds, do not need to know the feed class.

The valid methods on feeds are:

  • PUT - creates a feed of the specified class, with the specified name. The method is idempotent (it can be repeated with no further effect).
  • GET - queries the specified feed. The method returns information about the feed. It is idempotent and has no side effects.
  • DELETE - deletes the specified feed. This method is idempotent. Implicitly deletes any joins made onto the feed.

Further, applications can also use these methods on feed classes:

  • GET - queries the feed class. This method returns the set of feeds defined in that class. It is idempotent and has no side effects.

Feed names may not contain /, #, @, or spaces.

The response to a PUT is a content

<?xml version="1.0"?><restms version="1.0" status="ok"><pipe name="6VVFHDQWQYV3SB4L1" uri="http://localhost:8080/pipe/6VVFHDQWQYV3SB4L1" messages="0"/></restms>

Pipes

The URI for a pipe takes this form:

/restms/{pipe-class}/{pipe-name}

The set of valid pipe classes, and their meaning, are defined later. Each pipe class defines a particular set of semantics for the pipes it contains. Applications can create and delete pipes at runtime.

The valid methods on pipes are:

  • PUT - creates client-named pipe of the specified class. The method is idempotent.
  • GET - queries the specified pipe. The method returns information about the pipe. It is idempotent and has no side effects.
  • DELETE - deletes the specified pipe. This method is idempotent.

Further, applications can also use these methods on pipe classes:

  • GET - queries the pipe class. This method returns information about the pipe class. It is idempotent and has no side effects.
  • PUT - creates a server-named pipe. This method returns the name for the new pipe. It is not idempotent - each such PUT method will create a new pipe.

Applications should delete pipes when they are finished using them. However, RestMS server implementations will normally do housekeeping on pipes, and automatically delete pipes that are unused for a certain time, or which have overflowed beyond some configured limit. A RestMS server should be stable over time, even if applications do not clean up their resources.

Pipe names may not contain /, #, @, or spaces.

Addresses

Every message in a feed has an address, and when applications wish to receive messages from a feed they specify which addresses they are interested in. Thus, all applications using a particular feed will agree in advance on the set of possible addresses, and their significance. This is a pure application concern.

An address URI resembles an email address. It consists of an address string, an 'at' sign, and the name of a feed and optionally a feed class:

/restms/{address-string}@{feed-name}[/{feed-class}]

The only method allowed on an address is:

  • POST - send the message to the feed, addressed using the specified address string.

If the URI specifies a feed class, the feed will be created if it does not exist, and if the feed exists, the POST method will check that the feed class matches (and reply with a PRECONDITION error if not).

Note that the feed class comes after, not before the feed name. In this URI, the feed class is not the container for the feed, so is not specified as a parent.

Address strings may not be empty, and may not contain /, #, @, or spaces.

Joins

Joins regulate how messages are routed from feeds into pipes. Applications access joins via their pipes, that is, pipes are the containers for joins. The URI for a join consists of a pipe URI followed by an address (an address string, an 'at' sign, and a feed name and optional feed class):

/restms/{pipe-class}/{pipe-name}/{address-string}@{feed-name}[/{feed-class}]

The valid methods on joins are:

  • PUT - creates a join as specified. The method is idempotent. The PUT method creates the pipe if the pipe does not already exist. It also creates the feed if the feed does not exist, and a feed class is specified. If the feed exists and the URI includes a feed class, the method asserts that the class matches.
  • GET - queries the specified join. The method returns information about the join. It is idempotent and has no side effects. The feed, pipe, and join must all exist. If the URI includes a feed class, the method asserts that the class is accurate.
  • DELETE - deletes the specified join. This method is idempotent. None of the feed, pipe, nor join need exist. If the method includes a feed class and the feed and the join exist, the delete method will first check that the class is accurate before proceding.

The full join URI is the most complex RestMS URI, as it defines a relationship between two objects. The feed class comes after, not before the feed name since in this URI the feed class is not the container for the feed.

The address strings in a join URI are patterns rather than literal strings. The actual meaning of the pattern depends on the feed class. An example is a topic matching class, where a subscriber would create a join on the address "*.USD" a a publisher might post to an address "GOLD.USD".

Nozzles

A nozzle regulates the flow of messages off pipes to applications. Messages are the discrete packages of data sent between applications and routed across RestMS servers. They are unnamed binary blobs and cannot be directly addressed. Applications access messages via nozzles, that is, nozzles are the containers for messages. The URI for a nozzle consists of a pipe URI followed by nozzle name and optional message :

/restms/{pipe-class}/{pipe-name}/{nozzle}[/{index}]

These are the valid methods on a nozzle:

  • GET - gets a message from the nozzle. Will wait for a message to arrive on the pipe, and will take a message off the pipe, if necessary.
  • DELETE - deletes the nozzle and all messages it contains, in effect acknowledging that the messages were successfully processed. This method is idempotent.

The GET method always waits if it cannot deliver a message immediately. RestMS applications do not poll for messages. The client can use its own timeouts to break the connection at any time. Note that nozzles, once created, will continue to wait for messages, and applications that decide to stop waiting on a nozzle should delete it.

The simplest use of a nozzle is to get one message and then confirm that message:

GET /restms/pipe/my.pipe/my.nozzle/0
... process message ...
DELETE /restms/pipe/my.pipe/my.nozzle/0

An index '/0', or an unspecified index both mean 'get the first message'. These two methods are equivalent:

GET /restms/pipe/my.pipe/my.nozzle
GET /restms/pipe/my.pipe/my.nozzle/0

The GET nozzle method has the side effect of pulling one or more messages from the pipe into the nozzle, but is idempotent. If executed more than once successively, will return the same message twice. The DELETE method is also safe to invoke multiple times with no further consequences.

A more sophisticated use of a nozzle is to get a series of messages and then confirm them in a single step:

GET /restms/pipe/my.pipe/my.nozzle/0
... process message ...
GET /restms/pipe/my.pipe/my.nozzle/1
... process message ...
GET /restms/pipe/my.pipe/my.nozzle/2
... process message ...
GET /restms/pipe/my.pipe/my.nozzle/3
... process message ...
GET /restms/pipe/my.pipe/my.nozzle/4
... process message ...
DELETE /restms/pipe/my.pipe/my.nozzle

The index is a numeric value starting at 0. GET methods may be received and processed out of order. Applications can skips indices. The DELETE method will delete even undelivered messages in that case. The following is valid and will result in one thousand messages being taken off the pipe, and a single one (the the 1000th message) delivered to the application:

GET /restms/pipe/my.pipe/my.nozzle/999
DELETE /restms/pipe/my.pipe/my.nozzle

If the RestMS implementation destroys the nozzle before receiving a DELETE method, any messages it holds will be returned to the pipe for future delivery.

For convenience, the nozzle name may be empty, in which case the index may not be specified. This allows a short URI for retrieving and confirming individual messages:

GET /restms/pipe/my.pipe/
... process message ...
DELETE /restms/pipe/my.pipe/

Applications MUST NOT share nozzles. The effects of sharing a nozzle are arbitrary and undefined. If two applications wish to share a pipe they MUST agree in advance on unique nozzle names.

Pipe semantics

As for feeds, pipe semantics are defined explicitly in the URI according to the pipe class specified by the caller. RestMS defines two pipe classes:

  • pipe - delivers individual messages. One GET method results in one message.
  • stream - delivers multiple messages. One GET method results in an open-ended stream of messages, delivered to the client application as multipart chunked contents.

The pipe class must be used consistently in all URIs that refer to a pipe. It is invalid (BADREQUEST) to create a pipe using one class name and access it using a different class name.

The stream class does not allow nozzles, and is intended for high-performance delivery of messages to a single application, with no message acknowledgments. Streaming can be considered properly RESTful. Note that the streaming response format is not yet defined.

HTTP headers

RestMS uses certain HTTP headers to provide additional information, both on requests and responses. These headers obey the rules for application-defined HTTP headers:

  • RestMS-reply-to - specifies the reply-to property on messages. It is optional on POST address, and may be present in replies from GET message. The meaning of this field is application-defined.
  • RestMS-message-id - specifies the message-id property on messages. It is optional on POST address, and may be present in replies from GET message. The meaning of this field is application-defined.

Summary of URIs

This table shows the different URI types and the methods they allow:

Topology /restms GET
Feed class /restms/{feed-class} GET
Feed /restms/{feed-class}/{feed-name} PUT, GET, DELETE
Pipe class /restms/{pipe-class} GET, PUT
Pipe /restms/{pipe-class}/{pipe-name} PUT, GET, DELETE
Address /restms/{address-string}@{feed-name}[/{feed-class}] POST
Join /restms/{pipe-class}/{pipe-name}/{address-string}@{feed-name}[/{feed-class}] PUT, GET, DELETE
Nozzle /restms/{pipe-class}/{pipe-name}/{nozzle}[/{index}] GET, DELETE

The complete list of URI/method combinations is:

  • GET /restms - query RestMS topology.
  • GET /restms/{feed-class} - query feed class.
  • PUT /restms/{feed-class}/{feed-name} - create feed.
  • GET /restms/{feed-class}/{feed-name} - query feed.
  • DELETE /restms/{feed-class}/{feed-name} - delete feed.
  • GET /restms/{pipe-class} - query pipe class.
  • PUT /restms/{pipe-class} - create server-named pipe.
  • PUT /restms/{pipe-class}/{pipe-name} - create client-named pipe.
  • GET /restms/{pipe-class}/{pipe-name} - query pipe.
  • DELETE /restms/{pipe-class}/{pipe-name} - delete pipe.
  • POST /restms/{address-string}@{feed-name}[/{feed-class}] + CONTENT - post message to address.
  • PUT /restms/{pipe-class}/{pipe-name}/{address-string}@{feed-name}[/{feed-class}] - create join.
  • GET /restms/{pipe-class}/{pipe-name}/{address-string}@{feed-name}[/{feed-class}] - query join.
  • DELETE /restms/{pipe-class}/{pipe-name}/{address-string}@{feed-name}[/{feed-class}] - delete join.
  • GET /restms/{pipe-class}/{pipe-name}/{nozzle}[/{index}] - get message from nozzle.
  • DELETE /restms/{pipe-class}/{pipe-name}/{nozzle} - delete messages from nozzle.

AMQP interoperation

RestMS interoperates with AMQP through some basic conventions, some of which we've already explained.

  1. In general, AMQP and RestMS applications can freely interoperate, without knowledge of each others' particularities.
  2. RestMS publishers can address exchanges, or shared queues by name. They cannot address shared queues via arbitrary routing keys.
  3. RestMS supports all exchanges which route on a single string address, but not currently support the AMQP headers exchange.
  4. RestMS does not yet support message properties. So, these will be blank on messages originating from RestMS publishers, and will be ignored by RestMS consumers.

There are several possible architectures for message delivery from an AMQP server to a RestMS server. The simplest model is a single connection, which carries all messages. Messages are then distributed to pipes in the RestMS server. If multiple pipes request the same messagem, the message will be sent multiple times down the connection. In this model, the consumer-tag on Basic.Deliver methods tells the RestMS server how to route messages to pipes. The format of the consumer tag is 'prefix:pipe-name' where 'prefix' is a string that does not include the ':' character. (The prefix may be needed to ensure unique consumer tags.)

An alternative model is to open multiple connections or channels, e.g. one per pipe, and to use these to segment messages per pipes. Again, the same message may be sent many times if requested by multiple pipes.

The optimal, but most complex model, is to use federation-style normalization. In this model, the RestMS server maintains its own routing data structures, and forwards binding requests to the AMQP server. When messages arrive, they are routed not on consumer tag, but according to the message routing key and/or other properties. This model demands that the RestMS implementation has the same routing capabilities as the AMQP server, i.e. implements exchanges and shared queues in much the same way. The advantage of this model is that it allows for stand-alone RestMS operation, and is the optimal design for RestMS-to-RestMS interoperation (with no extra hops to and from the AMQP server).

Appendix

This is the RestMS class used to provide safe, idempotent access to RestMS resources on an AMQP server:

<?xml version="1.0"?>
<!--
    Copyright (c) 1996-2007 iMatix Corporation

    This program 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 2 of the License, or (at
    your option) any later version.

    This program 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.

    For information on alternative licensing for OEMs, please contact
    iMatix Corporation.
 -->
<class
    name    = "restms"
    handler = "connection"
    index   = "61501"
  >
  RestMS resource discovery and management class.

<doc>
    Provides methods to work with server-side resources as defined by
    the RestMS specification.  All methods are request-only, without
    response.  Errors are logged at the server side and not reported
    to the client.  This model is designed to allow a RestMS server to
    push state to the AMQP server, rapidly and without handshaking.
    In future versions we may allow for asynchronous error reporting
    back to the RestMS server, probably via an AMQP exchange.  The
    order of fields follows the URI component order for resources
    (esp. joins, which have complex URI construction).
</doc>

<doc name = "grammar">
    restms              = C:PIPE-CREATE
                        / C:PIPE-DESTROY
                        / C:FEED-CREATE
                        / C:FEED-DESTROY
                        / C:JOIN-CREATE
                        / C:JOIN-DESTROY
</doc>

<chassis name = "server" implement = "MAY" />
<chassis name = "client" implement = "MAY" />

<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

<method name = "pipe-create" index = "10">
  create a pipe
  <doc>
  Creates a pipe of the specified class.  The pipe may already exist,
  if it has the same class.  Pipe names are unique across all classes.
  </doc>
  <chassis name = "server" implement = "MUST" />
  <field name = "pipe class" type = "shortstr" >
    pipe class
    <doc>
    Specifies the class of the pipe to create.  Valid values are: pipe.
    </doc>
  </field>
  <field name = "pipe name" type = "shortstr" >
    Name of pipe
    <doc>
    Specifies the name of the pipe to create.  Pipe names may not contain
    slashes, spaces, or at signs.
    </doc>
  </field>
</method>

<method name = "pipe-delete" index = "20">
  delete a pipe
  <doc>
  Deletes a specified pipe, if it exists.  Safe to invoke on non-existent
  or already-deleted pipes.
  </doc>
  <chassis name = "server" implement = "MUST" />
  <field name = "pipe name" type = "shortstr" >
    pipe name
    <doc>
    Specifies the name of the pipe to delete.
    </doc>
  </field>
</method>

<method name = "feed-create" index = "30">
  create a feed
  <doc>
  Creates a feed of the specified class.  The feed may already exist,
  if it has the same class.  Feed names are unique across all classes.
  </doc>
  <chassis name = "server" implement = "MUST" />
  <field name = "feed class" type = "shortstr" >
    Feed class
    <doc>
    Specifies the class of the feed to create.  Valid values are: fanout,
    direct, topic, headers, rotator, and service.
    </doc>
  </field>
  <field name = "feed name" type = "shortstr" >
    Name of feed
    <doc>
    Specifies the name of the feed to create.  Feed names may not contain
    slashes, spaces, or at signs.
    </doc>
  </field>
</method>

<method name = "feed-delete" index = "40">
  delete a feed
  <doc>
  Deletes a specified feed, if it exists.  Safe to invoke on non-existent
  or already-deleted feeds.
  </doc>
  <chassis name = "server" implement = "MUST" />
  <field name = "feed name" type = "shortstr" >
    feed name
    <doc>
    Specifies the name of the feed to delete.
    </doc>
  </field>
</method>

<method name = "join-create" index = "50">
  create a join
  <doc>
  Creates a join on the specified pipe and feed.  The join may already
  exist, if it has the same properties.  A join will causes messages to
  be delivered on the connection.  The consumer-tag property allows
  messages to be routed into end-application pipes.  Joins on exchange
  feeds use the consumer tag "x:{pipe-name}" and joins on queue feeds
  use the consumer tag "q:{pipe-name}".  AMQP does not allow the same
  tag to be used on multiple queues.
  </doc>
  <chassis name = "server" implement = "MUST" />
  <field name = "pipe class" type = "shortstr" >
    Pipe class
    <doc>
    Specifies the class of the pipe, which must match the class of the
    existing pipe.  The only valid value for this field is "pipe".
    </doc>
  </field>
  <field name = "pipe name" type = "shortstr" >
    Name of pipe
    <doc>
    Specifies the name of the pipe, which must exist.
    </doc>
  </field>
  <field name = "address" type = "shortstr" >
    Join address
    <doc>
    Specifies the address to join.  This is an address literal or
    pattern who's semantics depend on the feed class.  The address
    may not contain slashes, spaces, or at signs.
    </doc>
  </field>
  <field name = "feed name" type = "shortstr" >
    Name of feed
    <doc>
    Specifies the name of the feed, which must exist.
    </doc>
  </field>
  <field name = "feed class" type = "shortstr" >
    Feed class
    <doc>
    Specifies the class of the feed, which must match the class of the
    existing feed.
    </doc>
  </field>
</method>

<method name = "join-delete" index = "60">
  delete a join
  <doc>
  Deletes a specified join, if it exists.  Safe to invoke on non-existent
  or already-deleted joins, and referring to non-existent pipes and/or
  feeds.
  </doc>
  <chassis name = "server" implement = "MUST" />
  <field name = "pipe name" type = "shortstr" >
    Name of pipe
    <doc>
    Specifies the name of the pipe, which does not need to exist.
    </doc>
  </field>
  <field name = "address" type = "shortstr" >
    Join address
    <doc>
    Specifies the join address.
    </doc>
  </field>
  <field name = "feed name" type = "shortstr" >
    Name of feed
    <doc>
    Specifies the name of the feed, which does not need to exist.
    </doc>
  </field>
</method>

</class>
Add a New Comment