Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Qpid Wiki" for change 
notification.

The following page has been changed by kpvdr:
http://wiki.apache.org/qpid/AMQPVersion

New page:
= Approach to adding support for multiple AMQP versions into the broker =
I had intended to follow approach 2 below, however after some brainstorming, a 
better and more efficient approach has been proposed. The following is a 
summary of the possible courses of action.

Kim van der Riet
----
== 1. Present status: No AMQP version discrimination. ==
=== ADVANTAGES: ===
  a. Nothing changes in the code, and everyone keeps doing what they are 
already doing... ;-)
=== DISADVANTAGES: ===
  a. There is no easy way of hosting more than one version of AMQP at the same 
time in the broker.
  a. The code that touches the version-specific generated method body classes 
is scattered all over the place. This makes it difficult to maintain the code 
if there '''''is''''' a change to the AMQP protocol. In order to help conceive 
the scope of possible protocol changes (outside of any policy the AMQP WG may 
have in this regard) consider the following possible change types/scopes:
    1. A method call (class, method, fields, types) do not change, but the use 
or purpose of a field changes;
    1. A method call changes the type of one or more fields;
    1. A method call changes the number of fields (including by removing a 
field from one version to the next);
    1. A method call changes the order of the fields;
    1. A totally new method call is added;
    1. A method call is removed;
    1. A class is added;
    1. A class is removed;
    1. Any of 5-9 above in such a way as to alter the class/method numbers of 
unchanged elements (e.g. a class is removed, so class Basic changes from 60 to 
50)
                
== 2. Initial approach to solving problem: Namespace discrimination. ==
  a. In this approach, each version of the protocol is generated as before, but 
into a namespace unique to that version.
  a. The {{{ProtocolSession}}} objects are made version-aware, and carry the 
major and minor version numbers of the current session from the 
{{{ProtocolInitiation}}} objects used to start the session.
  a. The points in the code where version-specific method body objects and/or 
calls are made are moved into a single layer - the method handlers. Static 
function calls are added where necessary to instantiate and/or process these 
objects. Since the method handlers are version-aware, they would contain the 
logic to select the correct namespace.
  a. The generated code would contain additional methods which allow the fields 
within any method body to be accessed or set using a parametrized function 
call. This would aid the coding of the version-sensitive logic used in the 
method handlers.
{{{        
    +--------+       +---------+       +------------+       +---------+
    | Broker |       |  Method |       | Generated  |       | Encoder |
    | code   | <---> | Handler | <---> | MethodBody | <---> | Decoder |
    |        |       | classes |       |  classes   |       | classes |
    +--------+       +---------+       +------------+       +---------+
       1                1 set         n sets, 1/version    1 or possibly more
}}}
=== ADVANTAGES: ===
  a. Allows multiple AMQP versions to be used simultaneously in the broker.
  a. Isolates the scope of version-specific code to the method handlers, where 
hand-coded logic specific to the needs of individual AMQP versions may reside. 
This aids maintainability in the event of additional versions being 
added/versions being changed.
  a. Forces the code to choose a specific AMQP version to use the 
{{{MethodBody}}} classes.
  a. Works using existing code-generation system (XSLT).
=== DISADVANTAGES ===
  a. Code duplication: Since in most AMQP version changes, 90+% of the 
specification remains unchanged, the generated classes will contain mostly 
exact duplicates from version to version.
  a. The ideal system of version fallback (in which default behavior is to use 
the latest class and to hand-code logic only where differences exist) does not 
operate. Each version must be handled separately whether identical or not.
  a. The code using the parametrized function calls is more complex and not as 
easy to understand as direct calls.
        
== 3. Revised approach: Intelligent generation ==
  a. In this approach, the limitations of the existing XSLT code generation are 
removed. We assume that we can compare one version of the AMQP specification to 
another, and generate code for the latest version and code to handle only the 
differences between the latest and each earlier version. To achieve this, we 
conceptually refactor the XML specification file so that the version 
information is contained inside the elements instead of outside them. Then each 
version of the spec is added cumulatively to create a complete map of the 
specification. For example, assume the following simple example: {{{
AMQP 1.0:
Basic.Consume(Ticket ticket, Queue queue, ConsumerTag consumer_tag, NoLocal 
no_local, NoAck no_ack, bool exclusive, bool nowait);
AMQP 1.2:
Basic.Consume(Ticket ticket, Queue queue, ConsumerTag consumer_tag, int no_ack, 
bool exclusive, bool nowait, NoLocal no_local, int priority);
}}}
  would be refactored to something like (abbreviated):{{{
<AMQP>
  <class name="Basic>
    <version major="1" minor="0" num="60"/>
    <version major="1" minor="2" num="50"/>
    <method name="Consume">
      <version major="1" minor="0" num="20"/>
      <version major="1" minor="2" num="20"/>
      <field name="ticket" type="Ticket">
        <version major="1" minor="0" num="0"/>
        <version major="1" minor="2" num="0"/>
      </field>
      <field name="queue" type="Queue">
        <version major="1" minor="0" num="1"/>
        <version major="1" minor="2" num="1"/>
      </field>
      <field name="consumer_tag" type="ConsumerTag">
        <version major="1" minor="0" num="2"/>
        <version major="1" minor="2" num="2"/>
      </field>
      <field name="no_local" type="NoLocal">
        <version major="1" minor="0" num="3"/>
        <version major="1" minor="2" num="6"/>
      </field>
      <field name="no_ack" type="NoAck">
        <version major="1" minor="0" num="4"/>
      </field>
      <field name="no_ack" type="int">
        <version major="1" minor="2" num="3"/>
      </field>
      <field name="exclusive" type="bool">
        <version major="1" minor="0" num="5"/>
        <version major="1" minor="2" num="4"/>
      </field>
      <field name="nowait" type="bool">
        <version major="1" minor="0" num="6"/>
        <version major="1" minor="2" num="5"/>
      </field>
      <field name="priority" type="int">
        <version major="1" minor="2" num="7"/>
      </field>
    </method>
  </class>
</AMQP>
}}}
  This would result in the generation of only a single {{{MethodBody}}} class, 
and since all instances of this class are version-aware, each knows how to 
handle calls for a given version (pseudo-java):{{{#!java
class BasicConsumeBody extends AMQPMethodBody
{
    public int _major, _minor;
    public BasicConsumeBody(int major, int minor) {_major = major; _minor = 
minor;}
    public int getAMQPClass(){if (major == 1 && minor == 0) return 60; else 
return 50;} // the class number has changed!
    public int getAMQPMethod(){return 20;}

    public Ticket getTicket() {...}
    public Queue getQueue() {...}
    public ConsumerTag getConsumerTag() {...}
    public NoLocal getNoLocal() {....}
    public T getNoAck(Class<T>) {if (major == 1 && minor == 0)...} // NoAck 
changes type
    public boolean getExclusive() {...}
    public boolean getNoWait() {...}
    public int getPriority() throws Exception {if (major != 1 || minor != 2) 
throw...} // Priority field is in 1.2 only
    // also for setXXX() methods...
}
}}}
  Static functions would require major and minor to be passed to be able to 
operate.
  a.#2 As before, the {{{ProtocolSession}}} objects are made version-aware, and 
carry the major and minor version numbers of the current session from the 
{{{ProtocolInitiation}}} objects used to start the session.
  a. As before, the points in the code where version-specific method body 
objects and/or calls are made are moved into a single layer - the method 
handlers.
  a. If different versions of a particular method have additional and/or 
different parameters, the generated class may be thought of as a cumulative 
collection of all these parameters/types. Since the object is AMQP 
version-aware, it is possible for the handlers to know which fields to use 
and/or how to initialize/handle the unused fields for any call which addresses 
less than all the available fields. Possible courses of action include ignoring 
the unused field, or initializing it with a meaningful default. Making the 
field members of the class public would afford this flexibility, and the 
get/set methods could simply be viewed as convenience methods. Where the type 
of a field changes, the different fields would require some kind of 
name-mangling to indicate their type.
        
=== ADVANTAGES ===
  a. Only a single class for each method body
  a. Single get/set method for each field
  a. Common code is simple and remains unchanged from version to version
  a. Where a field type changes, a {{{Class<T>}}} type method is used; this 
will break all areas in the code which used to use this method, and 
conveniently indicate where hand-coded logic is required.
  a. Where there is a  field that is unique to a subset of versions, 
auto-generated code will throw an exception if it is invoked from a session of 
the wrong version. The addition of the exception will break the compilation 
(i.e. must be caught), and will indicate places in the code where hand-coded 
logic will be required.
  a. The existing handler code can remain substantially unchanged.
        
=== DISADVANTAGES ===
  a. Complexity...
  a. This generation is beyond the capabilities of XSLT (or would be 
inordinately difficult), and we would need to switch to either Python (or 
Jython) or a purpose-written Java generator to do the job.
  a. It is not clear from the interface what field is valid in what version. 
There has been some discussion on name-mangling to solve this, but the general 
dislike for name-mangling in general and the complexities it brings seem to 
outweigh any advantages... 
  a. A couple of other things I have not seen yet!

Reply via email to