
Monikers in the Bonobo Component System.
Miguel de Icaza (miguel@helixcode.com)

* Introduction

	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.
	
	Note: on this document I have ommited the IDL: prefix in the
	CORBA interface names as well as the version number of the
	interface in an attempt to simplify the topic being
	discussed. Exception environments are also omitted for
	brevity.

* Monikers - a user perspective

	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.

	Here is a list of stringified monikers, and an interpretation
	of it:

		file:quake-scores.gnumeric
			This would be a moniker that represents the
			file quake-scores.gnumeric

		oafid:GNOME:Gnumeric:WorkbookFactory:1.0:7cf6fb4d-c5a1-4ace-aa6a-4ece790138c9
			This moniker represents the Gnumeric Workbook
			factory object.

		oafid:GNOME:Gnumeric:WorkbookFactory:1.0:7cf6fb4d-c5a1-4ace-aa6a-4ece790138c9:new:
			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.

		file:/tmp/a.gz
			This represents the file in /tmp/a.gz

		file:/tmp/a.gz#gunzip
			This represents the decompressed stream of
			data from a.gz

		file:/tmp/a.gz#gunzip:streamcache
			This provides a cache on top of the
			decompressed stream of data for a.gz (the
			streamcache moniker is an in-proc component). 

		http://www.gnome.org
			This one represents the GNOME web site.

		evolution:Mail/Inbox
			This represents the Evolution Mail/Inbox
			folder

		file:quake-scores.gnumeric!January
			This represents the January Sheet in the
			quake-scores.gnumeric workbook.

		file:quake-scores.gnumeric!January!Winner
			This represents the cell whose name is
			"Winner" in the January sheet in the
			quake-scores.gnumeric workbook.

		file:quake-scores.gnumeric!January!Winner!Style!Font
			This represents the Font interface of the
			Style attached to the Winner cell.

		file:quake-scores.gnumeric!Jannuary!Winner!Style!BackgroundColor
			This represents the background color for the cell.

		http://www.gnome.org/index.html!title
			This represents the title element in the HTML
			web page at www.gnome.org

		file:toyota.xml!cars/car/model/
			The "cars/car/model" is an XPath expression
			that for locating a specific node in the
			toyota.xml file.

		config:*/Session/Calendar
			This represents a PropertyBag for the GNOME
			Calendar using the Local configuration system
			and using the settings stored in the Session
			domain. 

		oafid:Helix:Evolution:Wombat:1.0:7cf6fb4d-c5a1-4ace-1020-4ece790138c0:
			This represents the Evolution model server
			that stores all the per-user information.

		queue:oafid:Helix:Evolution:Wombat:1.0:7cf6fb4d-c5a1-4ace-1020-4ece790138c0:
			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.

		http://www.gnome.org/index.html.gz#gunzip#html:title
			This will reutrn the title element of the
			compressed HTML file at 
			http://www.gnome.org/index.html.gz

 		ftp://ftp.gnome.org/gnome-core-1.0.tar.gz#utar/gnome-core-1.0/ChangeLog
			A reference to the ChangeLog file contained in
			the compressed gnome-core-1.0.tar.gz tar file
			at ftp://ftp.gnome.org 

		desktop:Backgound
			The background object for the user's desktop.

		trashcan:
			The system trashcan.

		file:logo.png
			This represents the logo.png file.

		oafid:OAFIID:eog_viewer_factory:777e0cdf-2b79-4e36-93d8-e9d490c9c4b8:file:logo.png
			This specifies a specific image viewer to be
		   	used to display the file "logo.png", in this
		   	case the "EOG" program.

		file:logo.png!Zoom=2.0
			This represents the logo.png file in EOG at
			zoom level 2.0

		file:logo.png!Zoom=2.0,dither=max,notransparency
			The image logo.png is configured to be zoomed
			at 2.0 factor, to do maximum dithering and not
			use any transparency

	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. 

	Monikers typically are created either by using a Bonobo API
	call that transforms the stringified representation into an
	object (which exports the IDL:Bonobo/Moniker:1.0 interface),
	like this:

@example
	moniker = bonobo_moniker_client_new_from_name (moniker_string);
@example

	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:

@example
		Bonobo::Unknown control;

		control = moniker->resolve ("IDL:Bonobo/Control:1.0")
@example

	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.  

	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:

@example
		properties = moniker->resolve ("IDL:Bonobo/PropertyBag:1.0");
@example

	The resolution process might yield completely different
	objects.  

	The parsing and resolution process is all encapsulated into a
	single API call for your convenience: the bonobo_get_object
	function:

@example
		Bonobo::Unknown bonobo_object_get (char *moniker_string, char *interface);
@example
	
	Now, as I said, the resolution process might yield very
	different objects depending on the interface being requested,
	for example:

@example
		x = bonobo_object_get ("http://www.gnome.org", "IDL:Bonobo/Control:1.0")
		y = bonobo_object_get ("http://www.gnome.org", "IDL:Bonobo/Stream:1.0")
@example

	The "x" object might launch Mozilla which would in turn load
	www.gnome.org, and the returned object can be used as a Bonobo
 	Control, and used in your application as a widget.

	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.  

	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. 

* The Moniker parsing system

	During parsing the Moniker stringified, Bonobo will use the
	colon-terminated prefix as the toplevel moniker to be invoked
	for the resolution process. 

	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.

	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.

	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.

	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).

* Monikers as an object naming scheme

	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.

	This means that the resulting object from the moniker
	resolution will always support ref, unref and
	query_interface methods.
	
	The Moniker object naming scheme is:

@list
	* Extensible.  new entry point into the object naming
	   space can be created and installed into the
	   system.  

	   This is achieved by installing a a new component 

	* Hierarchical.  Monikers FIXME
@list

* Creating Monikers

	Monikers are created typically by API calls into the Bonobo
	runtime or by your own classes that implement monikers.

	FIXME: more.

* Object Name Space

	* Comparing the Moniker name space with the Unix Name Space

	 	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".

	 	The result of resolving the moniker is a
	 	Bonobo::Unknown object.

	 	Think of a moniker as a pathname.  And think of the
	 	binding process as the "open" system call on Unix.

@example
	 	     Unix Files 	           Monikers
	            -----------------------------------------------
Object naming:       path name                moniker string representation.
Binding function:    open(2)                  bonobo_get_object
Return value:        kernel file descriptor   Bonobo::Unknown CORBA reference
Binder:              Kernel VFS+each FS       bonobo_get_object+Bonobo::Moniker 
Persisting:          none                     Moniker::QI(Persist)

@example

	 	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.

* File Linking

	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.

	The source application would create a moniker for a given
	object that would fully identify it, and pass it trough a drag
	and drop operation or a cut and paste operation to the
	recipient application.
	
	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).  

	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. 

* Instance initialization

	Monikers can be used to initialize objects, as a way of
	passing arguments to your object.  This is coupled with the
	Bonobo/ItemContainer interface.

	FIXME: Examples.

* Resolution of a moniker against an interface

	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 "http://www.helixcode.com"
	string representation of a moniker.

	The string representation of the moniker can be resolved
	against the "Bonobo/Control" interface:

@example
	bonobo_get_object ("http://www.helixcode.com", "Bonobo/Control");
@example

	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.

	The logic for this lives on the http: moniker handler.

* Core monikers

	Bonobo ships with a number of moniker handlers: the file
	moniker, the item moniker, the oafid moniker and the new
	moniker. 

** The file moniker

	The file moniker is used to reference files.   For instance:

@example
		file:sales.gnumeric
@example

	The file moniker will scan its argument until it reaches the
	special characters `#' or `!' which indicate the end of the
	filename.  

	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.

** The item moniker

** The oafid moniker

** The "new:" moniker

	The new moniker requests from its parent the
	"Bonobo/GenericFactory" interface and invokes the method
	create_instance in the interface.

	Typically this moniker would be invoked like this:

@example
		bonobo_get_object ("oafid:XXXXXXXX:new:", iface);
@example

	In the example above "XXXXXXXX" 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.

	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: 

@list
	 	* activate object implementation from an executable.

	 	* activate object implementation from a shared
	 	  library. 

	 	* activate object implementation by launching another
	 	  object, and querying the launched object for the
	 	  ObjectFactory interface.
@list

	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.

* Adding moniker handlers to the system

* Ideal monikers:
	
	There are two moniker handlers that would be interesting to
	implement: the Configuration Moniker and the VFS moniker.

	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.

	I am convinced that this helps make the system more self
	consistant internally.

** The Configuration Moniker

	The configuration moniker is invoked by using the "config:"
	prefix.  The string afterwards is the configuration locator.
	The moniker should support being querried against the
	"IDL:Bonobo/Property:1.0" or "IDL:Bonobo/PropertyBag:1.0"
	depending on whether we are requesting a set of attributes, or
	a single attribute.

	For example, retrieving the configuration information for a
	specific configuration property in Gnumeric would work like
	this:

@example	
	Bonobo_Property auto_save;
	CORBA_Any value;
	
	auto_save = bonobo_get_object (
		"config:gnumeric/auto-save", "IDL:/Bonobo/Property:1.0");
	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");
@example
	
	In the above example, we first use the bonobo_get_object
	routine to locate the configuration object through its
	moniker.  The return value from the bonobo_get_object is of
	type Bonobo_Property which is the standard Bonobo way of
	manipulating properties.
	
	This has two main advantages:

@list
	 	* 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.

	 	  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).
	
	 	  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.
	
	 	  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.
	
	 	* 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.
@list

	The Bonobo::Property interface is pretty comprehensive, and should
	address most needs, the methods are:

@example
	string   get_name ();
	TypeCode get_type ();
	any      get_value ();
	void     set_value ();
	any      get_default ();
	string   get_doc_string ();
	long     get_flags ();
@example

	Now, this interface as you can see does not specify an
	implementation for the actual backend.  There are various
	possibilities.

	Handling of transactional changes to the configuration system
	can be achieved by the use of the set_values interface in the
	PropertyBag.  If the values being set are invalid, a proper
	exception can be thrown.

*** What about GConf?

   GConf is a configuration management infrastructure that provides
the following features:

@list
	* A schema system for specifying the various configuration
	  options, as well as their documentation and initial values
	  (default values).

	* A way for the system administrator to override values in a
	  system-wide fashion (this encompasses a network-wise setup
	  if desired).

	* A change notification system: applications might be
	  notified of changes to various values they might want to
	  keep track of. 
@list

    There are two drawbacks to GConf currently:

@list
	* 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.

	* 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. 
@list  

    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.

*** Configuration management: Open Issues

**** Specifying the location for configuration.

   The syntax for accessing the configuration has not been defined,
but we can cook this up pretty easily.

   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:

@example
	config:~/file.config!auto-save
@example

   It seems more natural to use the file moniker to provide this
information, for example:

@example
	file:~/file.config!config:auto-save
@example

   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. 

**** Transactional setting of values. 

	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:

@example
	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);
@example

	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.

	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:

@example
	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);
@example

	This would allow the listener code to batch all the expensive
	requests into a single pass. 

**** Configuration handlers

	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.

	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.

** The GNOME VFS becomes deprecated.

	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.

	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).

	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).

	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.

	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.

* Other monikers

	There is another family of moniker handlers that are worth
	stuyding.  The filtering moniker handlers and the caching
	moniker handlers.

** The propertycache: moniker

** The streamcache: moniker

** The #gunzip, #utar filtering monikers

	#utar also allows sharing of the same data across components. 

* The accidental invention.

	Monikers were invented originally in OLE2 to implement Object
	Linking.  The OLE2 programmers accidentally invented an object
	naming system.  

	This object naming system is not only very powerful, but it is
	extensible and it helps make the system more consistent.

* Open Issues

	We will need to research the implementation requirements for
	asyncronous parsing and resolution of Monikers.  

	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.

* Conclusion 

	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:
@list
		* Component initialization

		* Addressing objects

		* Addressing sub-objects in a compound document.

		* Implementing Object Linking.

		* Implementing nested objects, and nested handlers for
		  file systems.

@list

* Acknowledgements

	The Bonobo moniker implementation was done by Michael Meeks.

	The design for the Bonobo moniker system was done by Ettore
	Perazzoli, Michael Meeks and myself.
