|
Server : Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8e-fips-rhel5 DAV/2 PHP/5.2.17 System : Linux localhost 2.6.18-419.el5 #1 SMP Fri Feb 24 22:47:42 UTC 2017 x86_64 User : nobody ( 99) PHP Version : 5.2.17 Disable Function : NONE Directory : /proc/21585/root/usr/share/gtk-doc/html/libbonobo/ |
Upload File : |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Monikers in the Bonobo Component System</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.69.1">
<link rel="start" href="index.html" title="Libbonobo Reference Manual">
<link rel="up" href="monikers.html" title="Monikers">
<link rel="prev" href="monikers.html" title="Monikers">
<link rel="next" href="libbonobo-bonobo-moniker.html" title="BonoboMoniker">
<meta name="generator" content="GTK-Doc V1.7 (XML mode)">
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="chapter" href="general.html" title="General">
<link rel="chapter" href="factories.html" title="Objects, Factories, Reference Counting">
<link rel="chapter" href="property-bags.html" title="Property Bags, Events, Listeners">
<link rel="chapter" href="monikers.html" title="Monikers">
<link rel="chapter" href="streams.html" title="Storages and Streams">
<link rel="chapter" href="persist.html" title="Persistency">
<link rel="chapter" href="misc.html" title="Miscellaneous">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"><tr valign="middle">
<td><a accesskey="p" href="monikers.html"><img src="left.png" width="24" height="24" border="0" alt="Prev"></a></td>
<td><a accesskey="u" href="monikers.html"><img src="up.png" width="24" height="24" border="0" alt="Up"></a></td>
<td><a accesskey="h" href="index.html"><img src="home.png" width="24" height="24" border="0" alt="Home"></a></td>
<th width="100%" align="center">Libbonobo Reference Manual</th>
<td><a accesskey="n" href="libbonobo-bonobo-moniker.html"><img src="right.png" width="24" height="24" border="0" alt="Next"></a></td>
</tr></table>
<div class="refentry" lang="en">
<a name="monikers-overview"></a><div class="titlepage"></div>
<p>Monikers in the Bonobo Component System.</p>
<p>Miguel de Icaza (miguel@ximian.com)</p>
<div class="refsect1" lang="en">
<a name="id2752783"></a><h2>Monikers in the Bonobo Component System</h2>
<div class="refsect2" lang="en">
<a name="id2752789"></a><h3>Introduction</h3>
<p>
We recently reimplemented and fully revamped the the
Moniker support in Bonobo. This work has opened a
wide range of possibilities: from unifying the object
naming space, to provide better integration in the
system. </p>
<p> Note: on this document I have ommited exception
environments handling for the sake of explaining the
technology.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2753416"></a><h3>Monikers - a user perspective</h3>
<p>
Monikers are used to name objects, they effectively
implement an object naming space. You can obtain
monikers either because you created the moniker
manually, or from a stringified representation of a
moniker.</p>
<p>Here is a list of stringified monikers, and an
interpretation of it:</p>
<div class="variablelist"><table border="0">
<col align="left" valign="top">
<tbody>
<tr>
<td>
<span class="term"><code class="literal">
file:quake-scores.gnumeric</code></span></td>
<td><p>
This would be a moniker that represents the
file <code class="filename">quake-scores.gnumeric</code>
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
oafid:GNOME:Gnumeric:WorkbookFactory:1.0</code></span></td>
<td><p>
This moniker represents the Gnumeric Workbook
factory object.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
oafid:GNOME:Gnumeric:WorkbookFactory:1.0:new:
</code></span></td>
<td><p>
This moniker represents a Gnumeric Workbook instance.
Notice that we are using the exact same OAFID
as the example before, but there is a "new:"
suffix at the end.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:/tmp/a.gz
</code></span></td>
<td><p>
This represents the file
in <code class="filename">/tmp/a.gz</code>.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:/tmp/a.gz#gunzip
</code></span></td>
<td><p>
This represents the decompressed stream of
data from <code class="filename">a.gz</code>.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:/tmp/a.gz#gunzip:streamcache
</code></span></td>
<td><p>
This provides a cache on top of the
decompressed stream of data
for <code class="filename">a.gz</code> (the streamcache
moniker is an in-proc component).
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
http://www.gnome.org
</code></span></td>
<td><p>
This one represents the GNOME web site.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
evolution:Mail/Inbox
</code></span></td>
<td><p>
This represents the Evolution Mail/Inbox
folder.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:quake-scores.gnumeric!January
</code></span></td>
<td><p>
This represents the January Sheet in the
<code class="filename">quake-scores.gnumeric</code> workbook.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:quake-scores.gnumeric!January!Winner
</code></span></td>
<td><p>
This represents the cell whose name is
"Winner" in the January sheet in the
<code class="filename">quake-scores.gnumeric</code> workbook.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:quake-scores.gnumeric!January!Winner!Style!Font
</code></span></td>
<td><p>
This represents the Font interface of the
Style attached to the Winner cell.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:quake-scores.gnumeric!Jannuary!Winner!Style!BackgroundColor
</code></span></td>
<td><p>
This represents the background color for the cell.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
http://www.gnome.org/index.html!title
</code></span></td>
<td><p>
This represents the title element in the HTML
web page at <code class="literal">www.gnome.org</code>.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:toyota.xml!cars/car/model/
</code></span></td>
<td><p>
The "cars/car/model" is an XPath expression
that for locating a specific node in the
<code class="filename">toyota.xml</code> file.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
config:*/Session/Calendar
</code></span></td>
<td><p>
This represents a PropertyBag for the GNOME
Calendar using the Local configuration system
and using the settings stored in the Session
domain.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
oafid:Helix:Evolution:Wombat:1.0
</code></span></td>
<td><p>
This represents the Evolution model server
that stores all the per-user information.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
queue:oafid:Helix:Evolution:Wombat
</code></span></td>
<td><p>
This represents an interface that queues CORBA
requests to the Evoution Wombat: Any calls
issued will be queued: if the Wombat is busy
or not accepting connection, all the CORBA
method invocations will be queued without
stopping the execution of the client code.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
http://www.gnome.org/index.html.gz#gunzip#html:title
</code></span></td>
<td><p>
This will reutrn the title element of the
compressed HTML file at
<code class="literal">http://www.gnome.org/index.html.gz</code>
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
ftp://ftp.gnome.org/gnome-core-1.0.tar.gz#utar/gnome-core-1.0/ChangeLog
</code></span></td>
<td><p>
A reference to the ChangeLog file contained in
the compressed gnome-core-1.0.tar.gz tar file
at <code class="literal">ftp://ftp.gnome.org</code>.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
desktop:Backgound
</code></span></td>
<td><p>
The background object for the user's desktop.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
trashcan:
</code></span></td>
<td><p>
The system trashcan.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:logo.png
</code></span></td>
<td><p>
This represents the logo.png file.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
oafid:OAFIID:eog_viewer_factory:file:logo.png
</code></span></td>
<td><p>
This specifies a specific image viewer to be
used to display the file "<code class="literal">logo.png</code>", in this
case the "EOG" program.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:logo.png!Zoom=2.0
</code></span></td>
<td><p>
This represents
the <code class="filename">logo.png</code> file in EOG
at zoom level 2.0.
</p></td>
</tr>
<tr>
<td>
<span class="term"><code class="literal">
file:logo.png!Zoom=2.0,dither=max,notransparency
</code></span></td>
<td><p>
The image logo.png is configured to be zoomed
at 2.0 factor, to do maximum dithering and not
use any transparency.
</p></td>
</tr>
</tbody>
</table></div>
<p>
Now, what you saw above are some examples of
stringified representations of monikers. This means
that they are not really monikers, it is the way a
Moniker is represented in string form.
</p>
<p>
Monikers typically are created either by using a
Bonobo API call that transforms the stringified
representation into an object (which exports the
<code class="literal">IDL:Bonobo/Moniker:1.0</code> interface),
like this:
</p>
<pre class="programlisting">
moniker = bonobo_moniker_client_new_from_name (moniker_string);
</pre>
<p>
Now, a moniker is only interesting because it can
yield other objects when resolved. During the
resolution process, you specify which interface you
are intersted on the moniker to return. This is
achieved by invoking the ::resolve method on the
moniker and passing the repoid of the interface you
desire, like this:</p>
<pre class="programlisting">
Bonobo::Unknown control;
control = moniker->resolve ("Bonobo/Control")
</pre>
<p> This would request the moniker to return an object
that implements the IDL:Bonobo/Control:1.0 interface.
This means that the object could be embedded as a
regular Bonobo control in applications.</p>
<p> Maybe you do not want to get a control, but rather
to resolve the moniker against a different interface,
for instance a Bonobo::PropertyBag interface:</p>
<pre class="programlisting">
properties = moniker->resolve ("Bonobo/PropertyBag");
</pre>
<p>The resolution process might yield completely different
objects.</p>
<p>The parsing and resolution process is all
encapsulated into a single API call for your
convenience: the bonobo_get_object function:</p>
<pre class="programlisting">
Bonobo::Unknown bonobo_object_get (char *moniker_string, char *interface);
</pre>
<p> Now, as I said, the resolution process might yield
very different objects depending on the interface
being requested, for example:</p>
<pre class="programlisting">
x = bonobo_object_get ("http://www.gnome.org", "Bonobo/Control")
y = bonobo_object_get ("http://www.gnome.org", "Bonobo/Stream")
</pre>
<p>The "x" object might launch Mozilla which would in turn load
<code class="literal">www.gnome.org</code>, and the returned
object can be used as a Bonobo Control, and used in
your application as a widget.</p>
<p> The "y" object on the other hand does not need all
the power of Mozilla, we are only requesting the very
simple Stream interface, so we might be able to
implement this with a lightweight HTTP implementation:
maybe a wget-based bonobo server, or a libghttp
server. </p>
<p> Note that even if the stringified versions of the
monikers were the same (ie, "http://www.gnome.org")
the resulting objects might differ wildely depending
on the interface being requested. </p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754098"></a><h3>The Moniker parsing system</h3>
<p>During parsing the Moniker stringified, Bonobo will
use the colon-terminated prefix as the toplevel
moniker to be invoked for the resolution process.</p>
<p>For the prefix "file:" the file moniker will be used; For the
prefix "oafid", the oafid moniker will be used; For the
"queue:" prefix, the queue moniker will be used.</p>
<p>Once the moniker that handles a specific prefix has
been activated, the moniker will be requested to parse
the remaining of the string specification and return a
valid moniker.</p>
<p>Each moniker typically will consume a number of
bytes up to the point where its domain stops, will
figure out what is the next moniker afterwards. Then
it will activate the next moniker and pass the
remaining of the moniker stringified version until the
parsing is finished.</p>
<p>Each moniker is free to define its own mechanism for parsing,
its special characters that are used to indicate the end of a
moniker space, and the beginning of a new one (like the "#"
and the "!" characters in some of the examples above). This
flexibility is possible because each moniker gets to define
its rules (and this is important, as we want to integrate with
standards like http and file).</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754140"></a><h3>Monikers as an object naming scheme</h3>
<p>As you can see, monikers are used to implement a
naming system that can be used to reference and
manipulate objects. As you might have noticed, the
::resolve method on the Moniker interface returns a
Bonobo::Unknown interface. And by definition, the
bonobo_get_object also returns a Bonobo::Unknown.</p>
<p>This means that the resulting object from the
moniker resolution will always support ref, unref and
query_interface methods.</p>
<p>The Moniker object naming scheme is:</p>
<div class="variablelist"><table border="0">
<col align="left" valign="top">
<tbody>
<tr>
<td>
<span class="term">Extensible</span></td>
<td><p> A new entry point into the
object naming space can be created and
installed into the system.</p></td>
</tr>
<tr>
<td>
<span class="term">Hierarchical</span></td>
<td><p> Monikers. </p></td>
</tr>
</tbody>
</table></div>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754197"></a><h3>Creating Monikers</h3>
<p>Monikers are created typically by API calls into the
Bonobo runtime or by your own classes that implement
monikers.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754211"></a><h3>Object Name Space</h3>
<div class="refsect3" lang="en">
<a name="id2754216"></a><h4>Comparing the Moniker name space with the
Unix Name Space</h4>
<p> Lets start simple. A moniker is a reference to
an object[1]. To actually use the object, you
have to "resolve" the moniker. The term used in
the literature is "binding the object". </p>
<p> The result of resolving the moniker is a
<code class="literal">Bonobo::Unknown</code> object.</p>
<p>Think of a moniker as a pathname. And think of the
binding process as the "open" system call on Unix.</p>
<p>Example:</p>
<div class="informaltable"><table border="0">
<colgroup>
<col>
<col>
<col>
</colgroup>
<tbody>
<tr>
<td> </td>
<td>Unix Files</td>
<td>Monikers</td>
</tr>
<tr>
<td>Object naming:</td>
<td>path name</td>
<td>moniker string representation</td>
</tr>
<tr>
<td>Binding function:</td>
<td>open(2)</td>
<td>bonobo_get_object</td>
</tr>
<tr>
<td>Return value:</td>
<td>kernel file descriptor</td>
<td>Bonobo::Unknown CORBA reference</td>
</tr>
<tr>
<td>Binder:</td>
<td>Kernel VFS+each FS</td>
<td>bonobo_get_object + Bonobo::Moniker</td>
</tr>
<tr>
<td>Persisting:</td>
<td>none</td>
<td>Moniker::QI(Persist)</td>
</tr>
</tbody>
</table></div>
<p>In the case of the file system, the kernel does
the "resolution" of each path element by parsing
one element of the file system, and the Virtual
File System switch uses the current file system +
mount points to resolve the ultimate file name.</p>
</div>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754365"></a><h3>File Linking</h3>
<p> Monikers were originally implemented as part of the
Microsoft OLE2 compound document system. They can be
used effectively by applications during drag and drop
and cut and paste operations to pass objects that must
be linked by other applications.</p>
<p>The source application would create a moniker for a
given object that would fully identify it, and pass it
through a drag and drop operation or a cut and paste
operation to the recipient application.</p>
<p>The recipient application then can resolve the
moniker against the interface required (in the Bonobo
case, Bonobo/Embeddable, or Bonobo/Control would be a
common choice).</p>
<p>Applications do not need to store the entire
contents of linked information, they can just store a
stringified representation of the moniker, and resolve
it again at load time.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754398"></a><h3>Instance initialization</h3>
<p>Monikers can be used to initialize objects, as a way
of passing arguments to your object. This is coupled
with the Bonobo/ItemContainer interface and the Item
Moniker.</p>
<p>The Item Moniker is covered later.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754414"></a><h3>Resolution of a moniker against an interface</h3>
<p>A moniker can be resolved against different
interfaces. The resulting object might be different
depending on the interface that is being resolved. To
illustrate this, here is an example, lets say we have
the <code class="literal">"http://www.helixcode.com"</code>
string representation of a moniker.</p>
<p>The string representation of the moniker can be resolved
against the "Bonobo/Control" interface:</p>
<pre class="programlisting">
bonobo_get_object ("http://www.helixcode.com", "Bonobo/Control");
</pre>
<p>This could return an embeddable Mozilla component
that is suitable to be embedded into your application
as a widget (because we are requesting the moniker to
return a Bonobo/Control interface). If the interface
is resolved against the "Bonobo/Stream"
interface,maybe Mozilla is not required, and the
process could use a smaller process that just provides
Bonobo/Streams, say a corbaified wget.</p>
<p>The logic for this lives on the http: moniker
handler.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754461"></a><h3>Core monikers</h3>
<p>Bonobo ships with a number of moniker handlers: the
<code class="literal">file</code> moniker,
the <code class="literal">item</code> moniker,
the <code class="literal">oafid</code> moniker and
the <code class="literal">new</code> moniker.</p>
<div class="refsect3" lang="en">
<a name="id2754494"></a><h4>The file moniker</h4>
<p>The file moniker is used to reference files.
For instance:</p>
<pre class="programlisting">file:sales.gnumeric</pre>
<p> The file moniker will scan its argument until
it reaches the special characters `#' or `!' which
indicate the end of the filename.</p>
<p>The file moniker will use the mime type
associated with the file to find a component that
will handle the file. Once the object handler has
been invoked, the Moniker will try to feed the
file to the component first through quering the
PersistFile interface, and if this is not
supported, through the PersistStream interface.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2754525"></a><h4>The item moniker</h4>
<p>The item moniker is typically triggered by the
"!" string in the middle. The item moniker can be
used to implement custom object naming, or
argument handling.</p>
<p>The item moniker parses the text following '!'
until the next '!' character, this is called the
argument of the item moniker. During the
resolution process, the item moniker will request
from its parent the Bonobo/ItemContainer interface
and will invoke the getObject on this interface
with the argument.</p>
<p>For example, in a Gnumeric spreadsheet this
allows programmers to reference sub-objects by
name. For instance, Workbooks can locate Sheet
objects; Sheets can locate range names, cell
names, or cell references.</p>
<p>This moniker would reference the sheet named
`Sales' in the workbook contained in the
sales.gnumeric spreadsheet:</p>
<pre class="programlisting">
sheet = bonobo_get_object ("sales.gnumeric!Sales", "Gnumeric/Sheet");
</pre>
<p>This other would reference the cell that has been named
`Total' inside the Sheet "Sales":</p>
<pre class="programlisting">
cell = bonobo_get_object ("sales.gnumeric!Sales!Total", "Gnumeric/Cell")
</pre>
<p> The way this works from the container
perspective, is that the container will implement
the <code class="function">getObject</code> (string)
method, and would respond to
the <code class="function">getObject</code> request.</p>
<p> Item monikers can also be used to perform
instance initialization. The component that wants
to support instance initialization needs to
support the Bonobo/ItemContainer interface and
implement a getObject method that would return the
object properly initialized.</p>
<p> For example, lets consider an image viewer
component that can be configured, like this: </p>
<pre class="programlisting">
image = bonobo_get_object ("file.jpg!convert_to_gray=on", "Bonobo/Control")
</pre>
<p>The above example would activate the EOG
component because of the file.jpg match, and then
invoke EOG's ItemContainer implementation with the
argument "convert_to_gray=on". getObject should
return an object (which would be itself) but it
would modify the instance data to set the
"convert_to_gray" flag to on. Like this:</p>
<pre class="programlisting">
Bonobo_Unknown
eog_item_container_get_object (BonoboObject *o, char *name)
{
if (command_is (name, "convert_to_gray", &v))
image_set_convert_to_gray (o, v);
...
bonobo_object_ref (o);
return bonobo_objet_corba_objref (o);
}
</pre>
</div>
<div class="refsect3" lang="en">
<a name="id2754635"></a><h4>The oafiid moniker</h4>
<p>The <code class="literal">oafid:</code> moniker handles
activation using the Object Activation Framework.
This allows application programmers to activate
objects by their OAF ID, like this:</p>
<pre class="programlisting">
gnumeric = bonobo_object_get ("oafiid:GNOME_Gnumeric_Workbook", iface)
</pre>
</div>
<div class="refsect3" lang="en">
<a name="id2754660"></a><h4>The "new:" moniker</h4>
<p>The new moniker requests from its parent the
"Bonobo/GenericFactory" interface and invokes the
method create_instance in the interface.</p>
<p>Typically this moniker would be invoked like this:</p>
<pre class="programlisting">
bonobo_get_object ("oafid:RandomFactory:new:", iface);
</pre>
<p>In the example above "RandomFactory" is the
OAFID for the factory for a certain object.
During the resolution process, the "new:" moniker
would request its parent to resolve against the
IDL:GNOME/ObjectFactory:1.0 interface (which is
the traditional factory interface in GNOME for
creating new object instances) and then invoke the
new_instance method on it.</p>
<p>Historically GNORBA (the old GNOME object
activation system) and OAF (the new object
activation system) implemented a special "hack" to
do this same processing. Basically, the
description files for the object activation system
was overloaded, there were three types of
activation mechanism defined:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>activate object implementation from an
executable.</p></li>
<li><p>activate object implementation from a
shared library.</p></li>
<li><p>activate object implementation by
launching another object, and querying the
launched object for the ObjectFactory
interface.</p></li>
</ul></div>
<p>The "new:" moniker basically obviates the need
for the last step in the activation system. With
OAF, using the OAF approach proves to be more
useful, as it is possible to query OAF for
components that have certain attributes, and the
attributes for a factory object are not as
interesting as the attributes for the instances
themselves. Despite this, the "new:" moniker can
be used for performing the operation of instance
initialization in more complex scenarios that go
beyond the scope of activation provided by
OAF.</p>
</div>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2754736"></a><h3>Adding moniker handlers to the system</h3>
<p><b>Ideal monikers: </b>There are two moniker handlers that would be
interesting to implement: the Configuration
Moniker and the VFS moniker.</p>
<p>They both help the system overall, because the added
simplicity of having a standard way of activating
services in the system and given that the API to these
services is CORBA-based, any programming language with
CORBA/Bonobo support can make use of them without the
need of a special language binding.</p>
<p>I am convinced that this helps make the system more
self consistant internally.</p>
<div class="refsect3" lang="en">
<a name="id2754766"></a><h4>The Configuration Moniker</h4>
<p>The configuration moniker is invoked by using
the <code class="literal">"config:"</code> prefix. The
string afterwards is the configuration locator.
The moniker should support being querried against
the "Bonobo/Property" or "Bonobo/PropertyBag"
depending on whether we are requesting a set of
attributes, or a single attribute.</p>
<p>For example, retrieving the configuration
information for a specific configuration property
in Gnumeric would work like this:</p>
<pre class="programlisting">
Bonobo_Property auto_save;
CORBA_Any value;
auto_save = bonobo_get_object (
"config:gnumeric/auto-save", "/Bonobo/Property");
value = bonobo_property_get_value (auto_save, &ev);
if (value-> tc-> kind == CORBA_tk_bool)
printf ("Value: %s\n", (CORBA_bool) value->_value ? "true" : "false");
else
printf ("Property is not boolean\n");
</pre>
<p> In the above example, we first use the
<code class="function">bonobo_get_object</code> routine to locate the
configuration object through its moniker. The
return value from the <code class="function">bonobo_get_object</code> is of type
<code class="literal">Bonobo_Property</code> which is the
standard Bonobo way of manipulating
properties.</p>
<p>This has two main advantages:</p>
<div class="itemizedlist"><ul type="disc">
<li>
<p>By accessing the configuration engine
through the moniker interface we have
eliminated the need to define a C-specific
API for the configuration management. The
configuration could have been reached
through any other programming language
that supports CORBA.</p>
<p>The GNOME project has always tried to
define APIs that could be easily wrapped
and accessed from various languages
(particularly, we have done this with the
toolkit and recently with the CORBA
bindings).</p>
<p>But even if we have taken special care
of doing this, and there are continous
efforts to wrap the latest and greatest
APIs, widgets, and tools, the bindings
typically lag a few weeks to monthsw
behind the actual C API.</p>
<p>By moving towards CORBA, we only need to
support CORBA in the various programming
languages and we get access to any new
APIs defined by it.</p>
</li>
<li><p>Any tools on the system that can
manipulate a Bonobo::Property or
::PropertyBag (a GUI in a visual designer,
or a configuration engine that
persists/hidrates objects, or a browsing
tool) can talk directly to the
configuration engine all of a sudden, as
we are using the same interface method
across every language on the system.</p></li>
</ul></div>
<p>The Bonobo::Property interface is pretty
comprehensive, and should address most needs, the
methods are:</p>
<pre class="synopsis">
string get_name ();
TypeCode get_type ();
any get_value ();
void set_value ();
any get_default ();
string get_doc_string ();
long get_flags ();
</pre>
<p>Now, this interface as you can see does not
specify an implementation for the actual backend.
Given that this is just an interface, we do not
care what the moniker will connect us to, we only
care with the fact that we will be able to use the
Property and PropertyBag interfaces.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2754910"></a><h4>Configuration transactions</h4>
<p>Handling of transactional changes to the
configuration system can be achieved by the use of
the setValues interface in the PropertyBag. The
implementation of the PropertyBag can either
accept the values set, or it can do consistency
checking of the values being set (for instance, to
avoid the configuration to contradict itself, or
store invalid values). If the values being set
are invalid, an exception is thrown.</p>
<p>It would be also possible to hook up an
arbitrary consistency checking component in the
middle, by inserting the consistency checking in
the middle of the stream, like this:</p>
<pre class="programlisting">
bonobo_get_object ("config:gnumeric/auto-save:gnumeric-consistency-check:", "Bonobo/Property");
</pre>
<p>Notice the `gnumeric-consistency-check:' moniker handler.
This could just be a shared library consistency checking
component if it needs to be.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2754947"></a><h4>Listening to changes.</h4>
<p>
One of the requirements for a modern desktop is to
be react globally when changes are made to global
settings. For example, in the GNOME desktop when
a theme is changed, a special protocol inside Gtk+
is used to notify all the applications that they
should reload their theme configuration.
</p>
<p>There are many other examples where applications
need to keep track of the current setting. For
example, when a preference is changed, we want the
preference to take place right away, without us
having to restart our running applications.
</p>
<p>This is easily achieved by registering a
Listener with the Bonobo/EventSource in the
PropertyBag.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2754975"></a><h4>What about GConf?</h4>
<p>GConf is a configuration management
infrastructure that provides the following
features:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>A schema system for specifying the
various configuration options, as well as
their documentation and initial values
(default values).</p></li>
<li><p>A way for the system administrator
to override values in a system-wide fashion
(this encompasses a network-wise setup if
desired).</p></li>
<li><p>A change notification system:
applications might be notified of changes to
various values they might want to keep track
of.</p></li>
</ul></div>
<p>There are two drawbacks to GConf currently:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>Although gconf provides pretty
much everything that is required, but it is a
C-based API that needs to be wrapped for every
language that wants to support GConf.</p></li>
<li><p>GConf is limited in the kind of
information that can be stored on its
database. A BonoboProperty stores a CORBA_Any
which can contain any of the simple CORBA
types (strings, integers, floating points,
booleans), structures, arrays and
unions.</p></li>
</ul></div>
<p>The actual engine and backend for GConf could
become the configuration moniker handler, only the
API would be replaced as well as the actual
storage system to support the more complete
CORBA_Any, and the ad-hoc CORBA interface can be
replaced with a more powerful system.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2755046"></a><h4>Configuration management: Open Issues</h4>
<p><b>Specifying the location for
configuration. </b>The syntax for accessing the configuration
has not been defined, but we can cook this up
pretty easily.</p>
<p>Forcing the configuration data to be loaded from
a specific location. Although the arguments to
the moniker could be used to encode a specific
location, for example:</p>
<pre class="programlisting">
config:~/file.config!auto-save
</pre>
<p> It seems more natural to use the file moniker
to provide this information, for example:</p>
<pre class="programlisting">
file:~/file.config!config:auto-save
</pre>
<p>The config moniker can test for the presence of
a parent, and if the parent exists, then it would
request one of the Persist interfaces from it to
load the actual configuration file, and provide
access to it.
</p>
<p><b>Transactional setting of values. </b>It might make sense to "batch" a number of
changes done under a prefix to avoid listeners
to a range of keys to reset themselves
multiple times. Consider the case in which a
command line tool makes various changes to the
background properties, say the changes are
done in this order:</p>
<pre class="programlisting">
background = bonobo_get_object ("config:desktop/background", "PropertyBag");
bonobo_property_bag_set_values (background,
bonobo_property_list_new (
"gradient", "string", "true",
"color1", "string" "red",
"color2", "string" "blue",
&ev);
</pre>
<p>If the real configuration program for handling
the background is running at that point, it will
have registered to be notified of changes to all
those values. The changes might be very
expensive. For example the code migh react to
every change and recompute the whole background
image on each change.</p>
<p>An optimization would be to tag the beginning of
the transaction and the end of it in the client
code to allow listeners to get batched
notification of changes:</p>
<pre class="programlisting">
background = bonobo_get_object ("config:desktop/background", iface);
bonobo_property_bag_batch_push (background);
bonobo_property_set (background, "gradient", "true");
bonobo_property_set (background, "color1", "red");
bonobo_property_set (background, "color2", "blue");
bonobo_property_bag_batch_pop (background);
</pre>
<p>This would allow the listener code to batch all
the expensive requests into a single pass.</p>
<p><b>Configuration handlers. </b>Consider the example above, we would like to
be able to change properties on the system and
have those properties to take effect
independently of whether a listener is
registered or not.</p>
<p>A property handler might register with the
configuration moniker to be launched when a
property changes. This could be done in a file
installed in a special location.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2755174"></a><h4>The GNOME VFS becomes deprecated.</h4>
<p>The GNOME VFS provides an asyncronouse
file-system interface abstraction that can be used
to access local files, remote files, files in
compressed files and more.</p>
<p>The problem with the GNOME VFS is that it is
very limited: it can only expose a file system
like interface to its clients (very much like the
Unix interface after which it was modeled).</p>
<p> As covered before in the `Object Naming Space',
Monikers define an object naming space, and
monikers can be defined for any type of resource
that the GNOME VFS supports (a transitional path
might include a set of monikers implemented on top
of the actual GNOME VFS).</p>
<p> A file dialog could request a moniker to be
resolved against a "Graphical File Listing"
interface, which might result in a miniature
Nautilus window to be embedded in the dialog
box.</p>
<p>It would be possible to entirely reuse the
existing GNOME VFS code by providing monikers for
the various access methods that would handle the
special cases "Stream", "Storage" and
"FileListing". Other interfaces will be plugged
into the moniker handler to support the richer
content.</p>
<p> For instance, consider the "trashcan:" moniker.
The trashcan moniker could be resolved against
various interfaces. A file manager would resolve
it against a DirectoryListing interface to display
the contents of it; It could resolve it against a
"Control" interface to get a trahscan custom view
(to configure the values in the trashcan); a
PropertyBag interface could be used to
programmatically configure the various settings in
it.</p>
</div>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2755229"></a><h3>Other monikers</h3>
<p>There is another family of moniker handlers that are
worth stuyding. The filtering moniker handlers and
the caching moniker handlers.</p>
<div class="refsect3" lang="en">
<a name="id2755239"></a><h4>The <code class="literal">streamcache:</code> moniker</h4>
<p>The idea of the streamcache: moniker is to be
basically a shared library moniker handler that
provides a cache for the IDL:Bonobo/Stream:1.0
interface.</p>
<p>This moniker is very simple, during resolution
it requests the IDL:Bonobo/Stream:1.0 interface
from its parent and it can only expose the
IDL:Bonobo/Stream:1.0 interface to clients.</p>
<p>The plus is this: it is a shared library
component, which will run in the address space of
the application that will use the Stream, and it
provides a cache to the parent Stream (so we can
use small granular method invocations, and the
stream cache can do the traditional buffering).</p>
<p> Think of this difference as the one between an
application using write()/read and the application
using fwrite/fread/getc/putc: although many
applications can implement their own buffering,
most of the time just using the libc-provided ones
(fwrite/fread/getc/putc) will do it. This is
exactly what the streamcache: moniker will do: By
appending this to a stringified representation of
a moniker, you can get a Stream cache for free.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2755284"></a><h4>The #gunzip, #utar filtering monikers</h4>
<p>The #utar moniker is a moniker that would
implement tar file decoding (the same concept can
be used for other archive formats). This moniker
uses an auxiliary tar component handler. The
moniker connects the tar component handler to the
parent object's Stream interface and returns the
resulting object. The result of the #utar moniker
can be either a Bonobo/Stream (for a file
reference) or Bonobo/Storage (for a directory
reference).</p>
<p>Like this:</p>
<pre class="programlisting">
file:/home/miguel/mail-backup.tar#utar:2000/may/1001
ftp://ftp.helixcode.com/pub/sources/gnome-libs-1.2.tar.gz#gunzip#utar:/README
</pre>
<p>The beauty of this system is that if two
applications use the same moniker, they would be
sharing the same data without having to uncompress
two times the same tar file.</p>
<p>This is all achieved transparently. This would
happen in quite a few instances, for example, if
you are exploring a compressed tar file in a file
manager and you drag the file to another
Moniker-aware application, say Gnumeric, Gnumeric
would be using the same file that was openened by
the file manager instead of having two
uncompressed sets of files in your system.</p>
<p>The above scenario is particularly useful if you
have little space, or if the process of untaring a
file would take a long time.</p>
</div>
<div class="refsect3" lang="en">
<a name="id2755335"></a><h4>The propertycache: moniker</h4>
<p>Accessing individual properties over and over
might take quite some time due to the CORBA round
trips. The propertycache: moniker would be also a
shared library handler that would basically
activate the property moniker, and would set up
property listeners (which would be notified of
changes in the property data base).</p>
<p>So if your application does a lot of queries to
a property, you might just want to append this to
improve performance and not care about doing
clustered reads, the cache would do this for
you.</p>
<p>This is not implemented, as it requires the
property moniker to be written.</p>
</div>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2755363"></a><h3>The accidental invention</h3>
<p>Monikers were invented originally in OLE2 to
implement Object Linking. The OLE2 programmers
accidentally invented an object naming system.</p>
<p>This object naming system is not only very powerful,
but it is extensible and it helps make the system more
consistent.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2755380"></a><h3>Monikers and the GNOME VFS</h3>
<p>
Some people ask: monikers look as if they are just
re-implementing the GNOME-VFS, why is that?</p>
<p>For a storage backend you can always use something
like bonobo_storage_new ("gnome-vfs") and get away
with life.</p>
<p>The main difference between the gnome-vfs, and
monikers is that monikers are used to implement an
object-based name space, while the gnome-vfs is a fine
abstraction for naming files and directories. The
moniker space goes well beyond this.</p>
<p>When Ettore, Nat and I designed the GNOME VFS in
Paris Ettore had a grander vision than Nat and I had.
Nat and I wanted exactly what the GNOME VFS is: an
asyncronous, pluggable virtual file system
implementation. Ettore wanted something more general,
something that would implement an object name space.
And some of the design decisions in the core of the
gnome-vfs reflect some of this thinking, but the API
and the infrastructure was limited to handling
files.</p>
<p>Various months later, we finally understood
completely the moniker system, and we realized that
monikers were an object naming space, and that if done
correctly monikers would be able to implement Ettore's
initial vision for having an object-based naming
space.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2755422"></a><h3>Open Issues</h3>
<p>We will need to research the implementation
requirements for asyncronous parsing and resolution of
Monikers.</p>
<p>Currently, both the Object Activation Framework and
Bonobo support asyncronous activation. Implementing
this for Monikers should not be hard, but might
require a few changes in the Moniker interface.</p>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2755440"></a><h3>Conclusion</h3>
<p>Monikers are very powerful mechanisms that can unify
the name space of objects in the system and can be
used to provide a uniform access method for a wide
variety of tasks:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>Component initialization</p></li>
<li><p>Addressing objects</p></li>
<li><p>Addressing sub-objects in a compound
document.</p></li>
<li><p>Implementing Object Linking.</p></li>
<li><p>Implementing nested objects, and nested handlers for
file systems.</p></li>
</ul></div>
</div>
<hr>
<div class="refsect2" lang="en">
<a name="id2755480"></a><h3>Acknowledgements</h3>
<p>The Bonobo moniker implementation was done by
Michael Meeks.</p>
<p>The design for the Bonobo moniker system was done by
Ettore Perazzoli, Michael Meeks and myself.</p>
</div>
</div>
</div>
</body>
</html>