Bug 1009984 - [amqp1.0] Update examples to amqp1.0 where the address string syntax differs
[amqp1.0] Update examples to amqp1.0 where the address string syntax differs
Status: CLOSED CURRENTRELEASE
Product: Red Hat Enterprise MRG
Classification: Red Hat
Component: Messaging_Programming_Reference (Show other bugs)
Development
Unspecified Unspecified
unspecified Severity medium
: 3.0
: ---
Assigned To: Jared MORGAN
Petr Matousek
:
Depends On:
Blocks: 957948 1010399
  Show dependency treegraph
 
Reported: 2013-09-19 12:04 EDT by Petr Matousek
Modified: 2015-08-09 21:23 EDT (History)
4 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2015-01-22 10:28:09 EST
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Petr Matousek 2013-09-19 12:04:02 EDT
Description of problem:

Inspect the example code in the Messaging Programming Reference Guide and provide amqp1.0 versions of examples where the address string syntax differs.

Currently amqp1.0 address string is incompatible in the following elements:
Link scoped x-declare
Node scoped x-bindings
Link scoped x-bindings
Delete policies

see bug 1009982 for details.

Please, provide examples update where applicable.

ie:
0-10 syntax:
rxheaders = ssn.receiver("match-q;{create: always, node: {type: queue}, link:{x-bindings:[{key: 'binding-name', exchange: 'amq.match', queue: 'match-q', arguments:{'x-match': 'any', 'header1': 'value1'}}]}}")

1.0 syntax:
rxheaders = ssn.receiver("match-q;{create: always, node: {type: queue}, link:{link:{filter:{value:{'x-match': 'any', 'header1': 'value1'}, name: headers, descriptor:"apache.org:xquery-filter:string"}}}}")

Version-Release number of selected component (if applicable):
Red Hat Enterprise MRG 3 - Messaging Programming Reference
Revision 0.0.0-2

How reproducible:
n/a

Steps to Reproduce:
n/a

Actual results:
some of the example code can't be used over amqp1.0

Expected results:
amqp1.0 compatible examples are provided where the syntax differs


Additional info:
Comment 6 Valiantsina Hubeika 2014-07-14 09:22:02 EDT
1.

Receiver receiver = session.createrReceiver("my-own-copy; {create: always, node:{type:queue}, link: {filter:{value:{'x-match': 'any', 'subject': 'quick-publish'}, name: headers, descriptor: "apache.org:xquery-filter:string"}]}}");

has two minor issues : '"' cannot be used within "" and  redundant ']', so the example should be  

Receiver receiver = session.createrReceiver("my-own-copy; {create: always, node:{type:queue}, link: {filter:{value:{'x-match': 'any', 'subject': 'quick-publish'}, name: headers, descriptor: 'apache.org:xquery-filter:string'}}}");


2. same issue with '"' in

Receiver rxheaders = ssn.createReceiver("amq.match; {link: {name:match-q, filter:{value:{'x-match': 'any', 'header1': 'value1'}, name: headers, descriptor:"apache.org:legacy-amqp-headers-binding:map"}}}");

should be 

Receiver rxheaders = ssn.createReceiver("amq.match; {link: {name:match-q, filter:{value:{'x-match': 'any', 'header1': 'value1'}, name: headers, descriptor:'apache.org:legacy-amqp-headers-binding:map'}}}");

3. missing '}' in

Receiver rxXML = ssn.createReceiver("myxml/weather; {link: {name:myxmlq, filter:{name:myfilter, descriptor:'apache.org:query-filter:string', value:'./weather'}}");

so it should be 

Receiver rxXML = ssn.createReceiver("myxml/weather; {link: {name:myxmlq, filter:{name:myfilter, descriptor:'apache.org:query-filter:string', value:'./weather'}}}");
Comment 8 Petr Matousek 2014-08-22 09:14:22 EDT
another portion of feedback:

1.) the issue 1. from comment 6 is still not fixed, there is typo createrReceiver instead of createReceiver (redundant character 'r').

the same applies to "4.8.6. Subscribe to a Topic Exchange":
Receiver rxnews = ssn.createrReceiver("amq.topic/#.news;{node:{capabilities:[shared]}, link:{name: 'news'}}");

2.) "3.6.2. "Hello World" Walk-through"

I believe it would be useful to add also amqp1.0 Connection example, ie:

connection = new Connection(broker);

optionally you may specify amqp1.0 protocol:
c++:
Connection connection(broker, "{protocol:amqp1.0}");
c#:
connection = new Connection(broker, "{protocol:amqp1.0}");

3.) "4.6.5. Subscribe to a Direct Exchange"

"Subscribing to a Direct Exchange using a Shared Queue" is a (sub)title and shall have different formatting (bold).

-> ASSIGNED
Comment 9 Petr Matousek 2014-08-22 09:19:27 EDT
4.) "4.6.5. Subscribe to a Direct Exchange"

Following example is listed on bad place, it belongs to "Subscribing to the Default Exchange using a Copy of Messages" section:
receiver = session.receiver('finance/reports')

Following example belongs to another chapter "4.5.3. Subscribe to the Default Exchange",  there is already a duplicate so it shall be just removed from "4.6.5. Subscribe to a Direct Exchange"
receiver = session.receiver('quick-publish; {mode: browse}')

Following example is completely messy, it does not either belong to this chapter (mixing headers/xquery filters, this is not related to direct exchange):
Receiver receiver = session.createrReceiver("my-own-copy; {create: always, node:{type:queue}, link: {filter:{value:{'x-match': 'any', 'subject': 'quick-publish'}, name: headers, descriptor: 'apache.org:xquery-filter:string'}}}");

Moreover there are many logical failures in this chapter (default exchange is used instead of direct in the shared queue example, filter used instead of shared capability, etc..), 

===

so summarizing, the chapter shall be completely rewritten and shall shall be updated following way:

<snip/>
...messages routed to an endpoint (note: exclusive are not supported by AMQP1.0). 

Subscribing to the Default Exchange using a Copy of Messages (** bold **)
This is the most straight-forward method to implement. 
Create a receiver and pass the name of the exchange together with the routing key to the constructor. For example, to obtain access to the queue "reports" of the "finance" direct exchange: 

{{{
Python
receiver = session.receiver('finance/reports')
}}}

Subscribing to a Direct Exchange using a Shared Queue (** bold **)
You need to subscribe to a queue, rather than to the exchange. 
Create a queue and bind it to the default exchange using a routing key. You can do that in one move using x-bindings. For example: 

{{{
AMQP 0-10
C++
Receiver receiver = session.createReceiver("my-own-copy;{create: always, node:{x-bindings: [{exchange: 'finance', key: 'quick-publish'}]}}");
}}}

We have created a shared queue named "my-own-copy" and bound it to the direct exchange with the key "quick-publish". 

AMQP 1.0
Node-scoped x-bindings are not supported in AMQP 1.0. Instead, use the shared capability:

{{{
C++
Receiver receiver = Receiver receiver = session.createReceiver("finance/quick-publish;{node: {capabilities:[shared]}, link: {name: 'my-own-copy'}}");
}}}
Comment 13 Gordon Sim 2014-08-22 10:01:36 EDT
(In reply to Petr Matousek from comment #9)
> so summarizing, the chapter shall be completely rewritten and shall shall be
> updated following way:
> 
> <snip/>
> ...messages routed to an endpoint (note: exclusive are not supported by
> AMQP1.0). 
> 
> Subscribing to the Default Exchange using a Copy of Messages (** bold **)

should be 'subscribing to a Direct Exchange' I think?

> This is the most straight-forward method to implement. 
> Create a receiver and pass the name of the exchange together with the
> routing key to the constructor.

Wording could be a little clearer, e.g. Create a receiver using an address comprised of the exchange name and the routing key.

> For example, to obtain access to the queue
> "reports" of the "finance" direct exchange: 

You aren't accessing a queue 'reports', your queue will be created and named for you and bound with the binding key 'reports'.

> 
> {{{
> Python
> receiver = session.receiver('finance/reports')
> }}}
> 
> Subscribing to a Direct Exchange using a Shared Queue (** bold **)
> You need to subscribe to a queue, rather than to the exchange. 

You can create a receiver from the exchange, just as with the previous example.

> Create a queue and bind it to the default exchange using a routing key. You
> can do that in one move using x-bindings.

Though you can do it this way, personally I think its clearer to merely specify the name and make the queue non-exclusive. E.g. instead of

> For example: 
> 
> {{{
> AMQP 0-10
> C++
> Receiver receiver = session.createReceiver("my-own-copy;{create: always,
> node:{x-bindings: [{exchange: 'finance', key: 'quick-publish'}]}}");
> }}}

Receiver receiver = session.createReceiver("finance/quick-publish;{link:{name:my-subscription, x-declare:{exclusive=False}}}");

I think the name 'my-own-copy' is not a good choice for demonstrating a shared subscription, so I changed that.
 
> We have created a shared queue named "my-own-copy" and bound it to the
> direct exchange with the key "quick-publish". 

See not above re suggested name change for queue. Worth adding the exchange name also, i.e. 'bound it to the direct exchange "finance" with...'

> AMQP 1.0
> Node-scoped x-bindings are not supported in AMQP 1.0. Instead, use the
> shared capability:
> 
> {{{
> C++
> Receiver receiver = Receiver receiver =
> session.createReceiver("finance/quick-publish;{node:
> {capabilities:[shared]}, link: {name: 'my-own-copy'}}");
> }}}

Same comment on name 'my-own-copy'. The suggested 0-10 form s much closer to this. We can note that link level x-declare clauses are not supported for 1.0, hence we request the capability of a shared subscription.

Hope this helps and is clear.
Comment 14 Petr Matousek 2014-08-22 11:46:39 EDT
so summarizing again with Gordon's feedback incorporated:
 
<snip/>
-
...messages routed to an endpoint.

+
...messages routed to an endpoint (note: exclusive binding are not supported by AMQP1.0).

Subscribing to the Default Exchange using a Copy of Messages (** bold **)
This is the most straight-forward method to implement. Create a receiver using an address comprised of the exchange name and the routing key.
For example, create a receiver on direct exchange "finance" using the "reports" key of intrest: 

{{{
Python
receiver = session.receiver('finance/reports')
}}}

Subscribing to a Direct Exchange using a Shared Queue (** bold **)

Subscription using a shared queue may be created by naming the subscription queue and defining it non-exclusive, 
For example:

{{{
C++
Receiver receiver = session.createReceiver("finance/quick-publish;{link:{name:my-subscription, x-declare:{exclusive:False}}}");
}}}

Alternativelly you may create a queue and bind it to the direct exchange using a routing key. You can do that in one move using x-bindings.
For example: 

{{{
C++
Receiver receiver = session.createReceiver("my-subscription;{create: always, node:{x-bindings: [{exchange: 'finance', key: 'quick-publish'}]}}");
}}}

We have created a shared queue named "my-subscription" and bound it to the direct exchange "finance" with the key "quick-publish". 

AMQP 1.0
Both Link-scoped x-declare and Node-scoped x-bindings clauses are not supported in AMQP 1.0, hence we request the capability of a shared subscription:

{{{
C++
Receiver receiver = Receiver receiver = session.createReceiver("finance/quick-publish;{node: {capabilities:[shared]}, link: {name: 'my-subscription'}}");
}}}
Comment 15 Petr Matousek 2014-08-22 11:49:31 EDT
(In reply to Petr Matousek from comment #14)
> so summarizing again with Gordon's feedback incorporated:
>  
> <snip/>
> -
> ...messages routed to an endpoint.

^^ I should have mentioned that content from here until the next section (4.6.6. Exclusive Bindings for Direct Exchanges) shall be replaced with the new content
Comment 18 Petr Matousek 2014-08-22 12:24:49 EDT
Also, the 'finance' direct exchange shall be create before the first use in "4.6.4. Publish to a Direct Exchange".

possibilities:

qpid-tools:
  qpid-config add exchange direct finance

c++:
  amqp0-10
    session.createSender('finance;{type: topic, x-declare: {type: direct}}')
  amqp1.0:
    session.createSender('finance;{type: topic, properties: {exchange-type: direct}}')

python:
    session.createSender('finance;{type: topic, x-declare: {type: direct}}')
Comment 21 Petr Matousek 2014-08-22 12:45:29 EDT
small correction for comment 18:

- python:
-    session.createSender('finance;{type: topic, x-declare: {type: direct}}')
+ python:
+    session.sender('finance;{type: topic, x-declare: {type: direct}}')
Comment 22 Petr Matousek 2014-08-27 11:10:16 EDT
here is the rest of issues found in the examples:

== 4.7.2. Fanout Exchange ==
'#' character shall be used instead of '*':

- Effectively, a Fanout Exchange is a Topic Exchange where all queues bound to the exchange use a wildcard of * as their binding key. 
+ Effectively, a Fanout Exchange is a Topic Exchange where all queues bound to the exchange use a wildcard of # as their binding key. 

== 4.9.5. Publish to a Headers Exchange ==
ommited session:

-  txheaders = sender("amq.match")
+  txheaders = ssn.sender("amq.match")

== 6.5.2. Automatically Deleted Queue Example == 

The example is not valid when using amqp1.0 protocol, please add the following note (feel free to rephrase the wording):

"... Our program has exited, but the queue has not been deleted because so far no-one has subscribed to it."

+ Note: There is a difference in the amqp1.0 behaviour. Using amqp0-10 the queue is deleted when not in use only if there have been consumers, using 
amqp1.0 the queue is deleted when not in use even if there have never been any consumers.

== 6.7.5. Fairshare Feature ==

both the examples are wrong, they're using address string syntax, but the syntax is not supported by qpid-config. A sender/receiver must be used here to make the examples working, ie:

- qpid-config add queue 'my-queue; {create: always, node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare: 5}}}}'

- qpid-config add queue 'my-queue; {create: always, node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare-0: 3, x-qpid-fairshare-1: 5, x-qpid-fairshare-2: 3, x-qpid-fairshare-3: 2, x-qpid-fairshare-4: 4, x-qpid-fairshare-5: 5, x-qpid-fairshare-6: 5, x-qpid-fairshare-7: 3, x-qpid-fairshare-8: 5, x-qpid-fairshare-9: 4, x-qpid-priorities: 10}}}}'

C++
+ Sender sender = session.CreateSender('my-queue; {create: always, node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare: 5}}}}'

+ Sender sender = session.CreateSender('my-queue; {create: always, node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare-0: 3, x-qpid-fairshare-1: 5, x-qpid-fairshare-2: 3, x-qpid-fairshare-3: 2, x-qpid-fairshare-4: 4, x-qpid-fairshare-5: 5, x-qpid-fairshare-6: 5, x-qpid-fairshare-7: 3, x-qpid-fairshare-8: 5, x-qpid-fairshare-9: 4, x-qpid-priorities: 10}}}}'

== 6.8.2. Create a Queue with Message Groups enabled ==

missing senders's type definition:

- groupedSender = session.createSender("my-grouped-msg-queue; {create:always, node: {x-declare: {auto-delete: True, arguments: {'qpid.group_header_key':'msgGroupID', 'qpid.shared_msg_group':1}}}}")
+ Sender groupedSender = session.createSender("my-grouped-msg-queue; {create:always, node: {x-declare: {auto-delete: True, arguments: {'qpid.group_header_key':'msgGroupID', 'qpid.shared_msg_group':1}}}}")

== ⁠8.2.1. Controlling Queue Size ==

missing "'" character:

- tx = ssn.sender("my-queue; {create: always, node: {x-declare: {'auto-delete': True, arguments:{'qpid.max_count': 5000, 'qpid.max_size': 204800, 'qpid.policy_type: 'ring'}}}}"
+ tx = ssn.sender("my-queue; {create: always, node: {x-declare: {'auto-delete': True, arguments:{'qpid.max_count': 5000, 'qpid.max_size': 204800, 'qpid.policy_type': 'ring'}}}}"

== 8.5.3. Create a durable queue in an application ==

missing '"' character:

- Sender sender = session.createSender("important-messages; {create:always, node:{durable: True})
+ Sender sender = session.createSender("important-messages; {create:always, node:{durable: True}")

- newqueue = session.sender("important-messages; {create:always, node:{durable: True})
+ newqueue = session.sender("important-messages; {create:always, node:{durable: True}")

== 9.2. QMF Versions ==

For more information on QMFv2, refer to the "Apache Qpid QMFv2 Project Page". 

^^ The link do not exist anymore and shall be updated to the new location: https://cwiki.apache.org/confluence/display/qpid/QMFv2+Project+Page

QMFv1 is not supported anymore, so the doc should change following way:
- QMFv1 calls are possible in Red Hat Enterprise Messaging, but they are not recommended. QMFv1 is deprecated and may be removed in a future release. 
+ QMFv1 is no longer supported in the Red Hat Enterprise Messaging.

== 9.6. QMF Command Message Structure ==
I believe it's worth adding the QMF _object_name format (feel free to rephrase the wording):
- ... a single value with the key _object_name containing the value org.apache.qpid.broker:broker:amqp-broker. 
+ ... a single value with the key _object_name containing the value org.apache.qpid.broker:broker:amqp-broker. The _obejct_name value has the following syntax 'package:class:id', desired value may be obtained from the schema ie. using qpid-tool.

The x-amqp-0-10.app-id is not set when using amqp1.0 protocol:
- The response message has the x-amqp-0-10.app-id property set to qmf2.
+ The response message has the x-amqp-0-10.app-id property set to qmf2 when using amqp0-10.

== 13.5. Qpid Maps and Lists in C++ ==
As set/getContentObject is now preffered approach the examples shall be updated following way:

- encode(content, message);
+ message.setContentObject(content);

(Maybe it is worth adding note that encode(content, message) method may be alternatively used)

== 14. The Request/Response Pattern ==
The second example needs to be updated following way to be both 0-10/1.0 compatible:

-  Address responseQueue("#response-queue; {create:always}");
-  Receiver receiver = session.createReceiver(responseQueue);

+ Receiver receiver = session.createReceiver("#response-queue; {create:always}");
+ Address responseQueue = receiver.getAddress();
Comment 23 Petr Matousek 2014-08-27 11:12:08 EDT
== 17.3. Change the logging level at runtime ==
In order to make the code amqp1.0 compatible two updates are needed:

responseQueue address must be obtained from the broker using receiver's getAddress() method:

- Address responseQueue("#reply-queue; {create:always, node:{x-declare:{auto-delete:true}}}");
- Receiver receiver = session.createReceiver(responseQueue);
+ Receiver receiver = session.createReceiver("#reply-queue; {create:always, node:{x-declare:{auto-delete:true}}}");
+ Address responseQueue = receiver.getAddress();

0-10 specific header check in qmf response need to be removed:

-    if (recv_props["x-amqp-0-10.app-id"] == "qmf2")
<snip/>
-    else
-      std::cerr << "Invalid response not of qmf2 type received!" << std::endl;

The set/getContent object is now preffered approach, so following change shall be also done:
- encode(content, message);
+ message.setContentObject(content);

So the example code shall be listed as follows:

#include <qpid/messaging/Connection.h>
#include <qpid/messaging/Session.h>
#include <qpid/messaging/Sender.h>
#include <qpid/messaging/Receiver.h>
#include <qpid/messaging/Message.h>
#include <qpid/messaging/Address.h>

#include <iostream>

using namespace std;
using namespace qpid::messaging;
using namespace qpid::types;

int main(int argc, char** argv) {
  if (argc < 2) {
    cerr << "Invalid number of parameters, expecting log level (info, trace, warning or so)" << endl;
    return 1;
  }
  string log_level = argv[1];

  Connection connection(argc>2?argv[2]:"localhost:5672");
  connection.open();
  Session session = connection.createSession();
  Sender sender = session.createSender("qmf.default.direct/broker");
  Receiver receiver = session.createReceiver("#reply-queue; {create:always, node:{x-declare:{auto-delete:true}}}");
  Address responseQueue = receiver.getAddress();

  Message message;
  Variant::Map content;
  Variant::Map OID;
  Variant::Map arguments;

  OID["_object_name"] = "org.apache.qpid.broker:broker:amqp-broker";
  arguments["level"] = log_level;

  content["_object_id"] = OID;
  content["_method_name"] = "setLogLevel";
  content["_arguments"] = arguments;

  message.setContentObject(content);
  message.setReplyTo(responseQueue);
  message.setProperty("x-amqp-0-10.app-id", "qmf2");
  message.setProperty("qmf.opcode", "_method_request");
  message.setContentType("amqp/map");

  sender.send(message, true);

  /* receive a response from the broker & check our request was successfully processed */
  Message response;
  if (receiver.fetch(response,qpid::messaging::Duration(30000)) == true) {
    qpid::types::Variant::Map recv_props = response.getProperties();
    if (recv_props["qmf.opcode"] == "_method_response")
      std::cout << "Response: OK" << std::endl;
    else if (recv_props["qmf.opcode"] == "_exception")
      std::cerr << "Error: " << response.getContent() << std::endl;
    else
      std::cerr << "Invalid response received!" << std::endl;
  }
  else
    std::cout << "Timeout: No response received within 30 seconds!" << std::endl;

  receiver.close();
  sender.close();
  session.close();
  connection.close();
  return 0;
}
Comment 24 Petr Matousek 2014-08-27 11:15:46 EDT
Summarizing - open issues are listed in the following comments:
  Comment 8
  Comment 14 + Comment 15
  Comment 18 + Comment 21
  Comment 22
  Comment 23
Comment 25 Jared MORGAN 2014-08-27 19:56:22 EDT
All comments relate to the deathstar version of the guide until such time that I have finished all peer review comments in this ticket.

http://deathstar1.usersys.redhat.com:3000/builds/19948-Messaging_Programming_Reference/

(In reply to Petr Matousek from comment #8)
> another portion of feedback:
> 
> 1.) the issue 1. from comment 6 is still not fixed, there is typo
> createrReceiver instead of createReceiver (redundant character 'r').
> 
> the same applies to "4.8.6. Subscribe to a Topic Exchange":
> Receiver rxnews =
> ssn.createrReceiver("amq.topic/#.news;{node:{capabilities:[shared]},
> link:{name: 'news'}}");

Both issues no longer present on Deathstar.

> 
> 2.) "3.6.2. "Hello World" Walk-through"
> 
> I believe it would be useful to add also amqp1.0 Connection example, ie:
> 
> connection = new Connection(broker);

This appears to be added in the second code block under C#/.NET tab. Is my understanding correct?

> 
> optionally you may specify amqp1.0 protocol:
> c++:
> Connection connection(broker, "{protocol:amqp1.0}");
> c#:
> connection = new Connection(broker, "{protocol:amqp1.0}");

This was already updated in the third code block under the respective tabs

> 
> 3.) "4.6.5. Subscribe to a Direct Exchange"
> 
> "Subscribing to a Direct Exchange using a Shared Queue" is a (sub)title and
> shall have different formatting (bold).

This appears to be fixed already.
Comment 26 Jared MORGAN 2014-08-27 20:10:57 EDT
(In reply to Petr Matousek from comment #14)
> so summarizing again with Gordon's feedback incorporated:
>  
> <snip/>
> -
> ...messages routed to an endpoint.
> 
> +
> ...messages routed to an endpoint (note: exclusive binding are not supported
> by AMQP1.0).
> 
> Subscribing to the Default Exchange using a Copy of Messages (** bold **)
> This is the most straight-forward method to implement. Create a receiver
> using an address comprised of the exchange name and the routing key.
> For example, create a receiver on direct exchange "finance" using the
> "reports" key of intrest: 
> 
> {{{
> Python
> receiver = session.receiver('finance/reports')
> }}}
> 
> Subscribing to a Direct Exchange using a Shared Queue (** bold **)
> 
> Subscription using a shared queue may be created by naming the subscription
> queue and defining it non-exclusive, 
> For example:
> 
> {{{
> C++
> Receiver receiver =
> session.createReceiver("finance/quick-publish;{link:{name:my-subscription,
> x-declare:{exclusive:False}}}");
> }}}
> 
> Alternativelly you may create a queue and bind it to the direct exchange
> using a routing key. You can do that in one move using x-bindings.
> For example: 
> 
> {{{
> C++
> Receiver receiver = session.createReceiver("my-subscription;{create: always,
> node:{x-bindings: [{exchange: 'finance', key: 'quick-publish'}]}}");
> }}}
> 
> We have created a shared queue named "my-subscription" and bound it to the
> direct exchange "finance" with the key "quick-publish". 
> 
> AMQP 1.0
> Both Link-scoped x-declare and Node-scoped x-bindings clauses are not
> supported in AMQP 1.0, hence we request the capability of a shared
> subscription:
> 
> {{{
> C++
> Receiver receiver = Receiver receiver =
> session.createReceiver("finance/quick-publish;{node:
> {capabilities:[shared]}, link: {name: 'my-subscription'}}");
> }}}

This was all incorporated in Docbuider. Note the double "Receiver receiver = Receiver receiver = in the AMPQ 1.0 example. Josh didn't incorporate that, but I noted that it might be required. Can you confirm please, Petr?
Comment 27 Jared MORGAN 2014-08-27 20:34:21 EDT
(In reply to Petr Matousek from comment #18)
> Also, the 'finance' direct exchange shall be create before the first use in
> "4.6.4. Publish to a Direct Exchange".
> 
> possibilities:
> 
> qpid-tools:
>   qpid-config add exchange direct finance
> 
> c++:
>   amqp0-10
>     session.createSender('finance;{type: topic, x-declare: {type: direct}}')
>   amqp1.0:
>     session.createSender('finance;{type: topic, properties: {exchange-type:
> direct}}')
> 
> python:
>     session.createSender('finance;{type: topic, x-declare: {type: direct}}')

From what I can see, Josh has already incorporated this on DeathStar unless I'm missing something.
Comment 28 Jared MORGAN 2014-08-27 20:35:24 EDT
(In reply to Petr Matousek from comment #21)
> small correction for comment 18:
> 
> - python:
> -    session.createSender('finance;{type: topic, x-declare: {type: direct}}')
> + python:
> +    session.sender('finance;{type: topic, x-declare: {type: direct}}')

Changes already made by Josh in DeathStar
Comment 29 Jared MORGAN 2014-08-27 20:51:35 EDT
(In reply to Petr Matousek from comment #22)
> here is the rest of issues found in the examples:
> 
> == 4.7.2. Fanout Exchange ==
> '#' character shall be used instead of '*':
> 
> - Effectively, a Fanout Exchange is a Topic Exchange where all queues bound
> to the exchange use a wildcard of * as their binding key. 
> + Effectively, a Fanout Exchange is a Topic Exchange where all queues bound
> to the exchange use a wildcard of # as their binding key. 
> 
> == 4.9.5. Publish to a Headers Exchange ==
> ommited session:
> 
> -  txheaders = sender("amq.match")
> +  txheaders = ssn.sender("amq.match")
> 
> == 6.5.2. Automatically Deleted Queue Example == 
> 
> The example is not valid when using amqp1.0 protocol, please add the
> following note (feel free to rephrase the wording):
> 
> "... Our program has exited, but the queue has not been deleted because so
> far no-one has subscribed to it."
> 
> + Note: There is a difference in the amqp1.0 behaviour. Using amqp0-10 the
> queue is deleted when not in use only if there have been consumers, using 
> amqp1.0 the queue is deleted when not in use even if there have never been
> any consumers.
> 
> == 6.7.5. Fairshare Feature ==
> 
> both the examples are wrong, they're using address string syntax, but the
> syntax is not supported by qpid-config. A sender/receiver must be used here
> to make the examples working, ie:
> 
> - qpid-config add queue 'my-queue; {create: always,
> node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare: 5}}}}'
> 
> - qpid-config add queue 'my-queue; {create: always,
> node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare-0: 3,
> x-qpid-fairshare-1: 5, x-qpid-fairshare-2: 3, x-qpid-fairshare-3: 2,
> x-qpid-fairshare-4: 4, x-qpid-fairshare-5: 5, x-qpid-fairshare-6: 5,
> x-qpid-fairshare-7: 3, x-qpid-fairshare-8: 5, x-qpid-fairshare-9: 4,
> x-qpid-priorities: 10}}}}'
> 
> C++
> + Sender sender = session.CreateSender('my-queue; {create: always,
> node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare: 5}}}}'
> 
> + Sender sender = session.CreateSender('my-queue; {create: always,
> node:{x-declare:{arguments:{qpid.priorities:10, x-qpid-fairshare-0: 3,
> x-qpid-fairshare-1: 5, x-qpid-fairshare-2: 3, x-qpid-fairshare-3: 2,
> x-qpid-fairshare-4: 4, x-qpid-fairshare-5: 5, x-qpid-fairshare-6: 5,
> x-qpid-fairshare-7: 3, x-qpid-fairshare-8: 5, x-qpid-fairshare-9: 4,
> x-qpid-priorities: 10}}}}'
> 
> == 6.8.2. Create a Queue with Message Groups enabled ==
> 
> missing senders's type definition:
> 
> - groupedSender = session.createSender("my-grouped-msg-queue;
> {create:always, node: {x-declare: {auto-delete: True, arguments:
> {'qpid.group_header_key':'msgGroupID', 'qpid.shared_msg_group':1}}}}")
> + Sender groupedSender = session.createSender("my-grouped-msg-queue;
> {create:always, node: {x-declare: {auto-delete: True, arguments:
> {'qpid.group_header_key':'msgGroupID', 'qpid.shared_msg_group':1}}}}")
> 
> == ⁠8.2.1. Controlling Queue Size ==
> 
> missing "'" character:
> 
> - tx = ssn.sender("my-queue; {create: always, node: {x-declare:
> {'auto-delete': True, arguments:{'qpid.max_count': 5000, 'qpid.max_size':
> 204800, 'qpid.policy_type: 'ring'}}}}"
> + tx = ssn.sender("my-queue; {create: always, node: {x-declare:
> {'auto-delete': True, arguments:{'qpid.max_count': 5000, 'qpid.max_size':
> 204800, 'qpid.policy_type': 'ring'}}}}"
> 
> == 8.5.3. Create a durable queue in an application ==
> 
> missing '"' character:
> 
> - Sender sender = session.createSender("important-messages; {create:always,
> node:{durable: True})
> + Sender sender = session.createSender("important-messages; {create:always,
> node:{durable: True}")
> 
> - newqueue = session.sender("important-messages; {create:always,
> node:{durable: True})
> + newqueue = session.sender("important-messages; {create:always,
> node:{durable: True}")
> 
> == 9.2. QMF Versions ==
> 
> For more information on QMFv2, refer to the "Apache Qpid QMFv2 Project
> Page". 
> 
> ^^ The link do not exist anymore and shall be updated to the new location:
> https://cwiki.apache.org/confluence/display/qpid/QMFv2+Project+Page
> 
> QMFv1 is not supported anymore, so the doc should change following way:
> - QMFv1 calls are possible in Red Hat Enterprise Messaging, but they are not
> recommended. QMFv1 is deprecated and may be removed in a future release. 
> + QMFv1 is no longer supported in the Red Hat Enterprise Messaging.
> 
> == 9.6. QMF Command Message Structure ==
> I believe it's worth adding the QMF _object_name format (feel free to
> rephrase the wording):
> - ... a single value with the key _object_name containing the value
> org.apache.qpid.broker:broker:amqp-broker. 
> + ... a single value with the key _object_name containing the value
> org.apache.qpid.broker:broker:amqp-broker. The _obejct_name value has the
> following syntax 'package:class:id', desired value may be obtained from the
> schema ie. using qpid-tool.
> 
> The x-amqp-0-10.app-id is not set when using amqp1.0 protocol:
> - The response message has the x-amqp-0-10.app-id property set to qmf2.
> + The response message has the x-amqp-0-10.app-id property set to qmf2 when
> using amqp0-10.
> 
> == 13.5. Qpid Maps and Lists in C++ ==
> As set/getContentObject is now preffered approach the examples shall be
> updated following way:
> 
> - encode(content, message);
> + message.setContentObject(content);
> 
> (Maybe it is worth adding note that encode(content, message) method may be
> alternatively used)
> 
> == 14. The Request/Response Pattern ==
> The second example needs to be updated following way to be both 0-10/1.0
> compatible:
> 
> -  Address responseQueue("#response-queue; {create:always}");
> -  Receiver receiver = session.createReceiver(responseQueue);
> 
> + Receiver receiver = session.createReceiver("#response-queue;
> {create:always}");
> + Address responseQueue = receiver.getAddress();

All issues incorporated by Josh in DeathStar.
Comment 30 Jared MORGAN 2014-08-27 21:36:09 EDT
(In reply to Petr Matousek from comment #23)
> == 17.3. Change the logging level at runtime ==
> In order to make the code amqp1.0 compatible two updates are needed:
> 
> responseQueue address must be obtained from the broker using receiver's
> getAddress() method:
> 
> - Address responseQueue("#reply-queue; {create:always,
> node:{x-declare:{auto-delete:true}}}");
> - Receiver receiver = session.createReceiver(responseQueue);
> + Receiver receiver = session.createReceiver("#reply-queue; {create:always,
> node:{x-declare:{auto-delete:true}}}");
> + Address responseQueue = receiver.getAddress();
> 
> 0-10 specific header check in qmf response need to be removed:
> 
> -    if (recv_props["x-amqp-0-10.app-id"] == "qmf2")
> <snip/>
> -    else
> -      std::cerr << "Invalid response not of qmf2 type received!" <<
> std::endl;
> 
> The set/getContent object is now preffered approach, so following change
> shall be also done:
> - encode(content, message);
> + message.setContentObject(content);
> 
> So the example code shall be listed as follows:
> 
> #include <qpid/messaging/Connection.h>
> #include <qpid/messaging/Session.h>
> #include <qpid/messaging/Sender.h>
> #include <qpid/messaging/Receiver.h>
> #include <qpid/messaging/Message.h>
> #include <qpid/messaging/Address.h>
> 
> #include <iostream>
> 
> using namespace std;
> using namespace qpid::messaging;
> using namespace qpid::types;
> 
> int main(int argc, char** argv) {
>   if (argc < 2) {
>     cerr << "Invalid number of parameters, expecting log level (info, trace,
> warning or so)" << endl;
>     return 1;
>   }
>   string log_level = argv[1];
> 
>   Connection connection(argc>2?argv[2]:"localhost:5672");
>   connection.open();
>   Session session = connection.createSession();
>   Sender sender = session.createSender("qmf.default.direct/broker");
>   Receiver receiver = session.createReceiver("#reply-queue; {create:always,
> node:{x-declare:{auto-delete:true}}}");
>   Address responseQueue = receiver.getAddress();
> 
>   Message message;
>   Variant::Map content;
>   Variant::Map OID;
>   Variant::Map arguments;
> 
>   OID["_object_name"] = "org.apache.qpid.broker:broker:amqp-broker";
>   arguments["level"] = log_level;
> 
>   content["_object_id"] = OID;
>   content["_method_name"] = "setLogLevel";
>   content["_arguments"] = arguments;
> 
>   message.setContentObject(content);
>   message.setReplyTo(responseQueue);
>   message.setProperty("x-amqp-0-10.app-id", "qmf2");
>   message.setProperty("qmf.opcode", "_method_request");
>   message.setContentType("amqp/map");
> 
>   sender.send(message, true);
> 
>   /* receive a response from the broker & check our request was successfully
> processed */
>   Message response;
>   if (receiver.fetch(response,qpid::messaging::Duration(30000)) == true) {
>     qpid::types::Variant::Map recv_props = response.getProperties();
>     if (recv_props["qmf.opcode"] == "_method_response")
>       std::cout << "Response: OK" << std::endl;
>     else if (recv_props["qmf.opcode"] == "_exception")
>       std::cerr << "Error: " << response.getContent() << std::endl;
>     else
>       std::cerr << "Invalid response received!" << std::endl;
>   }
>   else
>     std::cout << "Timeout: No response received within 30 seconds!" <<
> std::endl;
> 
>   receiver.close();
>   sender.close();
>   session.close();
>   connection.close();
>   return 0;
> }

This has been fixed by josh in the DeathStar version.
Comment 32 Petr Matousek 2014-08-28 12:23:44 EDT
Well, there are still following minor issues, after the fix for them this bug may go to verified.

1.) == General ==

There are multiple occurences of "session.CreateSender" (Capital 'C' is wrong)
All these occurences shall be updated accordingly (CreateSender -> createSender)

2.) == 4.6.4. Publish to a Direct Exchange ==

Following code example is missing create policy, 'node' key, assignment and programming lanuage header:

- session.sender('finance;node:{type: topic, x-declare: {type: direct}}')
+ * Python *
+ sender = session.sender('finance;{create:always, node: {type: topic, x-declare: {type: direct}}}')


3.) == 4.6.5. Subscribe to a Direct Exchange ==

a.) I'd like to request the following change to make the sentence more clear (feel free to rephrase the wording to make it more clear):

- The third pattern, exclusive binding, is where a consumer mandates that only consumer may have access to messages routed to an endpoint...
+ The third pattern, exclusive binding, is where a consumer mandates that only the consumer may have access to messages routed to an endpoint...

b.) The code exmaples are missing the programming language header.

c.) Moreover it's a bit complicated because different languages are used (first example is in python while the others are c++).
So I'm suggesting either to rewrite the first example to c++ or list both the languages (note: The last example is amqp1.0 only and thus shall be listed in c++ only). The programming languages switch may be easily done using the following replacement:

Python to C++: 
receiver = session.receiver('...') -> Receiver receiver = session.createReceiver('...')

C++ to python:
Receiver receiver = session.createReceiver('...') -> receiver = session.receiver('...')

4.) == 6.7.5. Fairshare Feature ==

Also missing programming language headers (they are in c++)

--

Also I'd like to appologise because the 1. and 2. are partially my fault because they come from the suggested changes from my side.
Comment 33 Jared MORGAN 2014-08-28 21:13:57 EDT
(In reply to Petr Matousek from comment #32)
> Well, there are still following minor issues, after the fix for them this
> bug may go to verified.
> 
> 1.) == General ==
> 
> There are multiple occurences of "session.CreateSender" (Capital 'C' is
> wrong)
> All these occurences shall be updated accordingly (CreateSender ->
> createSender)

I have corrected these instances. 

("new guy" observation here, Petr) I noticed that the sesson.CreateSession and session.CreateReceiver uses an upper-case first letter. Is the pattern for session.createSender relevant for these as well, or should they be uppercase?

> 
> 2.) == 4.6.4. Publish to a Direct Exchange ==
> 
> Following code example is missing create policy, 'node' key, assignment and
> programming lanuage header:
> 
> - session.sender('finance;node:{type: topic, x-declare: {type: direct}}')
> + * Python *
> + sender = session.sender('finance;{create:always, node: {type: topic,
> x-declare: {type: direct}}}')

Made a bit of an assumption here, and determined that the only block without a proglang heading was the block at the top of this section. I made the change to this block.

Added a comment in the docs code just in case I assumed wrong ;)

> 
> 
> 3.) == 4.6.5. Subscribe to a Direct Exchange ==
> 
> a.) I'd like to request the following change to make the sentence more clear
> (feel free to rephrase the wording to make it more clear):
> 
> - The third pattern, exclusive binding, is where a consumer mandates that
> only consumer may have access to messages routed to an endpoint...
> + The third pattern, exclusive binding, is where a consumer mandates that
> only the consumer may have access to messages routed to an endpoint...

Incorporated.

> 
> b.) The code exmaples are missing the programming language header.
> 
> c.) Moreover it's a bit complicated because different languages are used
> (first example is in python while the others are c++).
> So I'm suggesting either to rewrite the first example to c++ or list both
> the languages (note: The last example is amqp1.0 only and thus shall be
> listed in c++ only). The programming languages switch may be easily done
> using the following replacement:
> 
> Python to C++: 
> receiver = session.receiver('...') -> Receiver receiver =
> session.createReceiver('...')
> 
> C++ to python:
> Receiver receiver = session.createReceiver('...') -> receiver =
> session.receiver('...')

Thanks for the instructions here. Decided to add value for the customer and provide both code samples. Please review to ensure I haven't messed up the constructs.

I noted that C++ uses double-quotes and Python uses single-quotes (at least that's how it was originally. Should that be changed to single-quotes across all languages?

> 
> 4.) == 6.7.5. Fairshare Feature ==
> 
> Also missing programming language headers (they are in c++)

The previous change uses an XML structure that should be displaying the labels when published. I"ll check the build after writing this comment to ensure they are labelling correctly. 

> 
> --
> 
> Also I'd like to appologise because the 1. and 2. are partially my fault
> because they come from the suggested changes from my side.

No problem. Easy fixes.
Comment 34 Petr Matousek 2014-08-29 05:07:05 EDT
(In reply to Jared MORGAN from comment #33)
> (In reply to Petr Matousek from comment #32)
> > Well, there are still following minor issues, after the fix for them this
> > bug may go to verified.
> > 
> > 1.) == General ==
> > 
> > There are multiple occurences of "session.CreateSender" (Capital 'C' is
> > wrong)
> > All these occurences shall be updated accordingly (CreateSender ->
> > createSender)
> 
> I have corrected these instances. 
> 
> ("new guy" observation here, Petr) I noticed that the sesson.CreateSession
> and session.CreateReceiver uses an upper-case first letter. Is the pattern
> for session.createSender relevant for these as well, or should they be
> uppercase?

Good catch Jared, the syntax differs by programming language used, the .NET api uses Capital letters in these method calls while C++ api don't. So the syntax shall be following:

C++:  createSender, createReceiver, createSession
.NET: CreateSender, CreateReceiver, CreateSession

For more info please refer here:

C++ api reference:
http://qpid.apache.org/releases/qpid-0.22/messaging-api/cpp/api/classqpid_1_1messaging_1_1Session.html

.NET api reference:
http://qpid.apache.org/releases/qpid-0.22/messaging-api/dotnet/api/classOrg_1_1Apache_1_1Qpid_1_1Messaging_1_1Session.html
Comment 35 Petr Matousek 2014-08-29 07:15:39 EDT
add 1.) 
I've revised again the use of createX in C++ and C# examples and I've  located the following examples that needs correction:

3.6.1. Red Hat Enterprise Messaging "Hello World"

C#:
- Sender sender = session.createSender(address);  
+ Sender sender = session.CreateSender(address);  

13.7. Qpid Maps and Lists in .NET C#

- Sender sender = session.createSender(address);
+ Sender sender = session.CreateSender(address);


3.6.2. "Hello World" Walk-through

C#
- Sender sender = session.createSender(address);
+ Sender sender = session.CreateSender(address);

⁠4.1. Subscriptions

C#
- Sender sender = session.createSender(address);
+ Sender sender = session.CreateSender(address);

^^ two times in this cahpter

add 2.) ⁠4.6.4. Publish to a Direct Exchange

this chapter failed to compile:
ERROR: This topic doesn't have well-formed xml. The string "--" is not permitted within comments. 

http://deathstar1.usersys.redhat.com:3000/builds/19948-Messaging_Programming_Reference/#TagErrorXRef10226

add 3.) 
a.) ok, approved
b.) the 'programlisting' (programmning language header) was not seen neither on DeathStar nor on documentation-devel, is that expected atm?
c.) correct, C++ lang examples needs to use " character, python really  don't care if ' or " is given (thanks for choosing the best option to provide both python and c++ examples).

add 4.) same as 3b.
Comment 36 Jared MORGAN 2014-09-02 01:16:11 EDT
(In reply to Petr Matousek from comment #35)
> add 1.) 
> I've revised again the use of createX in C++ and C# examples and I've 
> located the following examples that needs correction:
> 
> 3.6.1. Red Hat Enterprise Messaging "Hello World"
> 
> C#:
> - Sender sender = session.createSender(address);  
> + Sender sender = session.CreateSender(address);

Josh must've got this one in the other ticket. It appears fixed for me in DeathStar.
  
> 
> 13.7. Qpid Maps and Lists in .NET C#
> 
> - Sender sender = session.createSender(address);
> + Sender sender = session.CreateSender(address);

Josh must've got this one in the other ticket. It appears fixed for me in DeathStar.
 
> 
> 3.6.2. "Hello World" Walk-through
> 
> C#
> - Sender sender = session.createSender(address);
> + Sender sender = session.CreateSender(address);

Josh must've got this one in the other ticket. It appears fixed for me in DeathStar.

> 
> ⁠4.1. Subscriptions
> 
> C#
> - Sender sender = session.createSender(address);
> + Sender sender = session.CreateSender(address);
> 
> ^^ two times in this chapter

Josh must've got this one in the other ticket. It appears fixed for me in DeathStar.

> 
> add 2.) ⁠4.6.4. Publish to a Direct Exchange
> 
> this chapter failed to compile:
> ERROR: This topic doesn't have well-formed xml. The string "--" is not
> permitted within comments. 
> 
> http://deathstar1.usersys.redhat.com:3000/builds/19948-
> Messaging_Programming_Reference/#TagErrorXRef10226

There is no validity issue being reported in DeathStar at the moment, so Josh must have fixed this last night on BZ#957948.

> 
> add 3.) 
> a.) ok, approved
> b.) the 'programlisting' (programmning language header) was not seen neither
> on DeathStar nor on documentation-devel, is that expected atm?

Seems that I used the incorrect arbitrary XML mark-up for those particular blocks, even though it was working in other topics. I've changed them to a different XML construct and hopefully this renders better.

Checked and it appears to be working well now: http://deathstar1.usersys.redhat.com:3000/builds/19948-Messaging_Programming_Reference/#Subscribe_to_a_Direct_Exchange

> c.) correct, C++ lang examples needs to use " character, python really 
> don't care if ' or " is given (thanks for choosing the best option to
> provide both python and c++ examples).

All good. Better for the customer!

So, I've rebuilt this book on docs-devel a few moments ago. The latest version will carry the 3.0.0-2 Revision History note.

http://documentation-devel.engineering.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_MRG/3/html-single/Messaging_Programming_Reference/index.html
Comment 37 Petr Matousek 2014-09-02 03:14:12 EDT
All the requested changes were properly incorporated except of comment 32 point 4. The program-listing works also well. After the easy fix for the issue above we may go to verified.

-> ASSIGNED
Comment 38 Jared MORGAN 2014-09-03 01:19:36 EDT
(In reply to Petr Matousek from comment #37)
> All the requested changes were properly incorporated except of comment 32
> point 4. The program-listing works also well. After the easy fix for the
> issue above we may go to verified.
> 
> -> ASSIGNED

Terrific, Petr. Thanks for your help getting this docs bug over the line. I love the way you take the time to explain the bugs and incorporations to make.

The final version on docs stage will carry the Revision number 3.0.0-3 or higher (depending on whether other changes in other bugs bump the rev number after this ticket is verified).
Comment 39 Petr Matousek 2014-09-03 10:37:06 EDT
All the issues were fixed. Approving VERIFIED status.

Note You need to log in before you can comment on or make changes to this bug.