NAME

Net::Jabber::Namespaces - In depth discussion on how namespaces are handled

SYNOPSIS

Net::Jabber::Namespaces is a pure documentation
module.  It provides no code for execution, just
documentation on how the Net::Jabber modules handle
namespaces.

DESCRIPTION

Jabber as a protocol is very well defined.  There are
three main top level packets (message, iq, and presence).
There is also a way to extend the protocol in a very
clear and strucutred way, via namespaces.

Two major ways that namespaces are used in Jabber is
for making the <iq/> a generic wrapper, and as a way
for adding data to any packet via <x/>.

The Info/Query <iq/> packet uses namespaces to determine
the type of information to access.  Usually there is
a <query/> tag in the <iq/> that represents the
namespace, but in fact it can be any tag.  The
definition of the Query portion, is the first
tag that has a namespace.

  <iq type="get"><query xmlns="..."/></iq>

    or

  <iq type="get"><foo xmlns="..."/></iq>

After that Query cna be any number of <x/> tags you want
to include.

The X tag is just a way to piggy back data on other
packets.  Like embedding the timestamp for a message
using jabber:x:delay, or signing you presence for
encryption using jabber:x:signed.

To this end, Net::Jabber has sought to find a way to
easily, and clearly define the functions needed to
access the XML for a namespace.  We will go over the
full docs, and then show two examples of real namespaces
so that you can see what we are talking about.

Overview

To avoid a lot of nasty modules populating memory that
are not used, and to avoid having to change 15 modules
when a minor change is introduced, the Net::Jabber
modules have taken AUTOLOADing to the extreme.
Query.pm, X.pm and Data.pm are nothing but a hash of
hashes data structure that is accessed by the Jabber.pm
AutoLoad function to do something.  (This will make
sense.)

Before going on, I highly suggest you read a Perl book
on AUTOLOAD and how it works.  From this point on I
will assume that you understand it.

When you create a Net::Jabber::IQ object and add a
Query to it (NewQuery) somethings are happening in
the background.  The argument to NewQuery is the
namespace you want to add. (jabber:iq:register)

Now that you have a Query object to work with you
will call the GetXXX functions, and SetXXX functions
to set the data.  There are no defined GetXXX and
SetXXXX functions.  You cannot look in the Query.pm
file and find them.  Instead you will find this:

$NAMESPACES{"jabber:iq:register"}->{Username}->{Get} = "username"; $NAMESPACES{"jabber:iq:register"}->{Username}->{Set} = ["scalar","username"]; $NAMESPACES{"jabber:iq:register"}->{Username}->{Defined} = "username"; $NAMESPACES{"jabber:iq:register"}->{Username}->{Hash} = "child-data";

When the GetUsername() function is called, the AUTOLOAD
function looks in the Query.pm %NAMESPACES hash for
a "Username" key, and then for a "Get" key under that.  It
will then use that value was the argument to a Get()
function defined in Jabber.pm.

Net::Jabber private namespaces

 Now this is where this starts to get a little sticky.
When you see a namespace with __netjabber__ at
the beginning it is usually something custom to
Net::Jabber and NOT part of the actual Jabber protocol.

There are some places where the structure of the XML
is a little more loose and not strongly structured.
While it is still strongly defined, it is not 100%
clear on how exactly to handle the tags.  The main
places you will see this behavior is where you have
multiple tags with the same name and those have
children under them (jabber:iq:roster), or where the
tags are not defined but are to be treated as children
just because they are there (jabber:iq:browse).

In jabber:iq:roster, the <item/> tag can be repeated
multiple times, and is sort of like a mini-namespace
in itself.  To that end, I treat it like a seperate
namespace and defined a __netjabber__:iq:roster:item
namespace to hold it.  What happens is this, in my code
I define that the <item/>s tag is "item" and anything
with that tag name is to create a new Net::Jabber::Query
object with the namespace __netjabber__:iq:roster:item
which then becomes a {query} child of the jabber:iq:roster
Query object.  Also, when you want to add a new item
to a jabber:iq:roster project you call NewQuery with
the private namespace.

In jabber:iq:browse, the children are not defined.
Any child node you see under that <iq/> tag defines
what the child type is.  So I again created a private
namespace, and add every child, except <ns/>, as a
new Queyr object.

I know this sounds complicated.  And if after reading
this entire document it is still complicated, email me,
ask questions, and I will monitor it and adjust these
docs to answer the questions that people ask.

Get() function

The values of the argument come in two forms, either a string
or an array.  For the most part, you will only use a string.
The string is the key into the hash in the Query object.
So above code would look into the Query hash for the
"username" key and return the value from there.  The string
also represents the value of the tag or attribute in the XML.

  "username" -> hash{username} -> <username/>

One of the functions introduced early on in the Net::Jabber
lifecycle was one that you could call and set all of the
values of an object.  SetIQ() in the IQ.pm module for
example.  Moving into this new AUTOLOAD format I added
a GetIQ() function that would return a hash with the values
populated as if you had called SetIQ().  This is done when
you set the string to "__netjabber__:master".  So for the
jabber:iq:register example above:

$NAMESPACES{"jabber:iq:register"}->{Register}->{Get} = "__netjabber__:master"; $NAMESPACES{"jabber:iq:register"}->{Register}->{Set} = ["master"];

GetReigster() would return a hash with the data in the
Query.

The second form is an array:
  [ key, namespace ]

like GetItem under the jabber:iq:search namespace:
  [ "query", "__netjabber__:iq:search" ]

This is used only when the GetXXXXX function is supposed
to return another object.  For example, under
jabber:iq:search, the agent can return multiple <item/>
tags.  These are turned in to Query objects as well and
stored in the {DATA}->{query} hash array.  The array value
tells the Get() function where to look "query", and which
Query objects to return, anything with the namespace
"__netjabber__:iq:search".

Set() function

This arguement value is always an array.  Though the
array can take a few forms depending on what you are
trying to set.

The first is the simplest, and the one you will more
than likely only use:

  [ type, key ]

In our jabber:iq:register example above {Username}->{Set}
is [ "scalar", "username" ].  The type is scalar, and
the key is username (again the key is the hash entry, and
the XML Tag or attribute).  The valid types are:

  scalar  - store the value as a string or number
  array   - store the value as an array (like in
            jabber:iq:roster with <group/>)
  flag    - sets the value to "" just to show that the
            XML should appear as a flag.  <tag/>
  jid     - Stores the value as a Net::Jabber::JID
            object
  master  - run through all of the SetXXXX functions
            and set the value based on the hash passed
            in as an argument.  (More on this below...)
  special - there are several cases where we want to
            default the value if there is none there.
            mainly used in the jabber:iq:time and
            jabber:iq:version functions, these will
            default the value to something that makes
            sense.  You will probably never use this.

As I mentioned, one of the functions introduced early on
in the Net::Jabber lifecycle was one that you could call
and set all of the values of an object.  SetIQ() in the
IQ.pm module for example.  This is where the "master"
type comes in.  When you declare that something is the
"master" it means that it can set all of the things in
the object via the SetXXXXXX functions based on the hash
that is passed to it.  So for jabber:iq:register:

$NAMESPACES{"jabber:iq:register"}->{Register}->{Set} = ["master"];

SetRegister(%hash) is considered to be the "master"
function for that namespace.

The second is more complicated and involves adding a new
XML child into the current tag.  This is only done
inside of the ParseTree function when taking XML and
building the Net::Jabber::xxxxxx objects that represent
the tree.  It takes the form:

  [ "add", object type, namespace ]
  [ "add", object type, namespace, tags to ignore ]

Looking at the jabber:iq:roster namespace:

$NAMESPACES{"jabber:iq:roster"}->{Item}->{Set} = ["add","Query","__netjabber__:iq:roster:item"];

A call to SetItem will add a new Net::Jabber::Query,
with the namespace __netjabber__:iq:roster:item, and
then populate the new Query object with the data you
passed to the SetItem function.  (This will be covered
more under the ParseTree function described at the end.)

Looking at the __netjabber__:iq:browse:item namespace:

$NAMESPACES{"__netjabber__:iq:browse"}->{Item}->{Set} = ["add","Query","__netjabber__:iq:browse","ns"];

Everything looks the same except for the extra "ns"
at the end.  This tells Net::Jabber that you can create
a new object from this XML data *UNLESS* the tag name
is <ns/>.  If you look at the jabber:iq:browse namespace
in the JPG, you will see that the children can have
any name, except for <ns/> which is used to define which
namespaces the jid provides.  (This will be covered
more under the ParseTree function described at the end.)

Defined() function

This function always takes a string as the argument.
The string is the key value for the data hash, and tells
Net::Jabber where to go look to see if the value is
defined.  This one should not need any more explantion
other than that.  All it does is check for exists() on
the data hash for this value.

Hash() function

This function takes only a string as its argument.
The value of the string determines how this bit
of data is handled when Net::Jabber attempts to read
or set the XML.  The valid values are:

  att             - in the parent XML this bit of
                    data is an attribute on the root
                    tag in the XML you are currently
                    processing.
  data            - in the parent XML this bit of
                    data is the CDATA of the root
                    tag in the XML you are currently
                    processing.
  child-data      - in the parent XML this bit of
                    data is the CDATA of a child tag
                    (defined by the NAMESPACES hash)
                    of the root tag in the XML you
                    are currently processing.
  child-flag      - in the parent XML this bit of
                    data says to include an empty child
                    tag (defined by the NAMESPACES hash)
                    of the root tag in the XML you
                    are currently processing.
  child-add       - in the parent XML this bit of
                    data says to create a new XML
                    child and populate it by recursing
                    and looking at the Hash() values
                    for its data.
  att-<tag>-<att> - in the parent XML this bit of
                    data says to set the <att>
                    attribute on the child with tag
                    <tag> in the root tag you are
                    currently processing.

I know this sounds really complicated, but its not.
Just look over the %NAMESPACES structures and think
about how the XML looks for the namespace you are
looking at.

Add() function

This function takes an array as its argument.  The array
has two very similer forms:

  [ object type, namespace, Set* function to call ]
  [ object type, namespace, Set* function to call, tag value ]

When the Add function gets called it will create a
Net::Jabber::"object type" object with the namespace
specified, and then call the SetXXXXX function based
on the third value.  If a tag value is specified in
the array, then that becomes the root tag for that
object, otherwise the first argument to the AddXXXXX
function defines the root tag.

Looking at the jabber:iq:roster namespace:

$NAMESPACES{"jabber:iq:roster"}->{Item}->{Add} = ["Query","__netjabber__:iq:roster:item","Item","item"];

A call to AddItem() will create a Net::Jabber::Query
object with __netjabber__:iq:roster:item as the namespace.
It will call SetItem on this new object to handle the
data passed to AddItem(), *AND* it will set the root
tag to "item" so that an <item/> tag is created.

Looking at the jabber:iq:browse namespace:

$NAMESPACES{"jabber:iq:browse"}->{Item}->{Add} = ["Query","__netjabber__:iq:browse","Browse"];

A call to AddItem() will create a Net::Jabber::Query
object with __netjabber__:iq:browse:item as the namespace.
It will call SetBrowse on this new object to handle the
data passed to AddItem().  The root tag of new object
is not defined though.  Instead, since the
jabber:iq:browse namespaces does not define the
children tags, and uses the value of the tag to
set what the browse item means, the call to AddItem()
must include the root tag as the first argument:

  my $browseItem =
    $browseQuery->
      AddItem("conference",
              type=>"private",
              jid=>"conference.jabber.org",
              name=>"Private Chatrooms");

ParseTree() function

This function you will never call, but it will
be calling the functions that you define in your
call to DefineNamespace.  We will quickly run through
how it works so you can get a better understanding
of how the all of the above fits together.

ParseTree() takes an XML::Stream::Hash tree and
runs through every function that hash a {Set} entry
in the definition Hash (see above).  For each
function it calls Hash() on that function name
to get the method of XML access for that function.
Based on that value, it reaches into the
XML::Stream::Hash and pulls the needed data out and
calls the appropritate SetXXXXXXX() function to store
that data.  If the Hash type is "child-add", then
it calls Add() and passes it the XML::Stream::Hash
tree with the {root} tag altered and ultimatly
ParseTree is called on that new tree and starts again.

After the defined {Set} functions have been looked at,
the function looks for any child tags that have xmlns
as an attribute.  If the current object is an <iq/>
then it treats the first tag with an xmlns as the
<query/> and creates that.  Otherwise, if the current
object is a Query object, then this must be a private
namespace for Net::Jabber, so create a Query object.
Finally, if that fails, and this is not the first
child with xmlns, or this is not a Query object then
create an X object.

Scrub.

Rinse.

Repeat.

Wrap Up

Well.  I hope that I have not scared you off from
writing a custom namespace for you application and
use Net::Jabber.  Look in the Net::Jabber::Protocol
manpage for an example on using the DefineNamespace
function to register your custom namespace so that
Net::Jabber can properly handle it.

AUTHOR

By Ryan Eatmon in May 2001 for http://jabber.org/

COPYRIGHT

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.