RE: Confusing about DBus API specification



On Thu, 2010-04-29 at 06:08 -0700, Nguyen Canh Toan wrote:
> Dear Jirka, 
> 
> It's weird. After adjusting my script, it's still error: 

D-Bus is simply an IPC mechanism, but it layers a few concepts on top of
pure message-passing, as explained below.  It did take me some time to
understand how the D-Bus object model really works, so don't worry about
it you don't completely understand how it all works yet.

1) 'service': a program that responds to requests from clients.  Each
service is identified by a "bus name" which clients use to find the
service and send requests to it.  The bus name usually looks like
"org.foobar.Baz".  A program can claim more than one bus name; NM claims
org.freedesktop.NetworkManager and
org.freedesktop.NetworkManagerSystemSettings, each is a unique serivce
which provides different functionality to clients.

2) 'object': a method of organizing distinct entities, much like
programming languages have objects.  Each object is uniquely identified
by an "object path" (basically a pointer) that looks like
"/org/foobar/Baz/235235". Each request sent to the service must be
directed to a specific object.  Many services have a base object with a
well-known path that you use to bootstrap your communication with the
service.

3) 'interface': each request belongs to an interface, which is simply a
way of logically separating different functionality.  The same way that
object-oriented languages like Java or C++ or GLib define an
"interface"; a specific API that different objects can implement, but
the caller doesn't need to know what type the object is, just the
interface.  Interface names often look like D-Bus service names, but
have no relation to them.

4) 'method call': a request for an operation or information that a
client sends to the service; method calls are defined by an Interface
and are sent to objects.

Say you have a binary called "mcdonaldsd" that provides a D-Bus service
called "org.fastfood.McDonalds".  Clients that want to talk to this
service use "org.fastfood.McDonalds" to direct requests to mcdonaldsd.

mcdonaldsd provides a base object called "/org/fastfood/McDonalds".
This object implements the "org.fastfood.McDonalds" interface, which
defines the method calls:

  - GetItems(void) -> ao
  - Order(ao) -> b

GetItems returns an array of object-paths representing all the things on
the menu that you can order.  So if you call it you'll get something
like this returned:

[ '/org/fastfood/McDonalds/Item/0', '/org/fastfood/McDonalds/Item/1' ]

Each of these returned object paths is a pointer to an object;
mcdonaldsd probably even implements these as objects internally using
Java or C++ or GObject or whatever.  These objects are probably
completely different (one may be a burger, one may be a drink) but they
all implement a common interface "org.fastfood.McDonalds.Item".

The org.fastfood.McDonalds.Item interface has the following method
calls:

  - GetName
  - GetType  (either TYPE_BURGER, TYPE_DRINK, or TYPE_FRIES)
  - GetPrice
  - Consume

So even if you don't know what /org/fastfood/McDonalds/Item/0 is, you
still can get a lot of information about it, enough to decide whether
you want to order it or not.

Assume that item "0" is a "BigMac" and item "1" is "Coke".  These are
clearly different objects, but each still has a name, a calorie count, a
price, and can be consumed.

Next, since each item is different (even though they all implement the
common org.fastfood.McDonalds.Item interface) each item type will
implement other interfaces that define functionality specific to that
type of item.

So item "0" (BigMac) implements the org.fastfood.McDonalds.Item.Burger
interface which has the following methods:

  - Unwrap
  - AddMustard
  - RemovePickle (nobody likes those stupid limp pickles anyway)

And item "1" (Coke) implements the org.fastfood.McDonalds.Item.Drink
interface which has the following methods:

  - PutLidOn
  - InsertStraw
  - RemoveStraw

Remember, since both objects *also* implement the base
org.fastfood.McDonalds.Item interface, you can use the Consume() method
to consume both items.  But clearly, you don't want to include the
InsertStraw() method on the generic org.fastfood.McDonalds.Item
interface, because all items implement that interface, and it would be
pretty funny if you tried to call InsertStraw() on the BigMac object.
People would stare.

So interfaces are about logically separating method calls that have
specific functionality, and thus any object that wants that
functionality can implement that interface, instead of having every
object type duplicate all the calls of that interface.

So, with pseudocode:

# Get local proxy for the remove mcdonaldsd service
bus = get_service("org.fastfood.McDonalds")
mcds = bus.get_object("org.fastfood.McDonalds", "/org/fastfood/McDonalds")

burger_path = None
drink_path = None

# Lets read all the menu items
menu_items = mcds.GetItems()
for object_path in menu_items:
    item = bus.get_object("org.fastfood.McDonalds.Item", object_path)
    print "Item: %s price %s" % (item.GetName(), item.GetPrice())

    # Now let's figure out what we want to order; we'll order
    # the first burger we find and the first drink we find, but
    # only one of each.  We just had breakfast so we're not that
    # hungry.
    item_type = item.GetType()
    if item_type == TYPE_BURGER and burger is None:
        burger_path = object_path
    elif item_type == TYPE_DRINK and drink is None:
        drink_path = object_path

    # We've found a burger and drink on the menu, lets order them
    if burger_path and drink_path:
        break

food = mcds.Order([burger_path, drink_path])
if food.len() == 0:
    print "Oops, not enough money or something. Need to get a job."
    sys.exit(1)

# Yay, we got our order.  Now we take off the damn pickle
burger = bus.get_object("org.fastfood.McDonalds.Item.Burger", burger_path)
burger.RemovePickle()

# And we're taking this to go, so we need a lid and straw for the drink
drink = bus.get_object("org.fastfood.McDonalds.Item.Drink", drink_path)

drink.InsertStraw()

try:
    drink.PutLidOn()
catch Exception, e:
    print "Oops, straw already inserted!"

# We're distracted by the smell of the burger and put the
# straw in before we put the lid on.  Oops.  Take the straw
# out, put the lid on, and then re-insert the straw
drink.RemoveStraw()
drink.PutLidOn()
drink.InsertStraw()

# All ready.  Now we can walk out and consume the burger and drink;
# note that even though burger_proxy and drink_proxy were created
# with D-Bus interfaces specific to their food type, we don't really
# need to create another interface just to call the generic Consume()
# method which both the burger and drink implement.  Just give the
# method call the generic interface.

burger.Consume(dbus_interface="org.fastfood.McDonalds.Item")
drink.Consume(dbus_interface="org.fastfood.McDonalds.Item")



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]