moniker/linking stuff...



Hi,


The folowing is a proposal for a Linking architecture in Bonobo.

0) details the problems this architecture solves.
1) details the CORBA interfaces which we will need to implement.
2) details the API developers will have to cope with.



0) problems
-----------

This architecture has 2 goals: 

	- provide a linking mechanism similar to OLE one.
	ie: file:///home/mathieu/bidule.gnumeric!Sheet1!A2:A8
	is a valid meaningfull link.
	- provide an easy to use/progressive API for application
	developers.


1) the interfaces
-----------------

1.0) introduction
-----------------
The folowing proposal is more or less a set of OLE interfaces
where all the useless/not-vital cruft was removed.

The Linking uses OLE Monikers and their binding mechanism as 
i explained in my previous mail on linking.

The rationale behind this design is to keep an Object Oriented 
approach. In OLE design, many methods belong to the Moniker 
interface but they don't have much to do with the Moniker 
object itself. They are there simply because one needs to 
call them. The result of this is that people were obliged
to have intimate knowledge of the objects to call some of their
methods. ex: the get_display method which required a Moniker
parameter to work. Now, these parameters are hard coded upon
creation/initialization of the Monikers by the MonikerFactory
interface.
This approach also makes it unecessary to have Composite 
Monikers because the Item Monikers allready who is at their left.


1.1) interfaces
---------------
module Bonobo {

	/**
	 * This interface is inherited by the MonikerFactory
	 * object and by the Bonobo::Container Object.
	 */
	interface ParseDisplayName : Object {
		/**
		 * parse_display_name:
		 *
		 * Returns a moniker from the string representation
		 * This is probably one of the most important method 
		 * here...
		 */
		Moniker parse_display_name (in string display_name,
					    out short display_name_bytes_parsed);
	}
	


	/**
	 * The base Factory for all monikers.
	 * There should be ONE instance of this
	 * object on the system.
	 */
	interface MonikerFactory : ParseDisplayName {
		/**
		 * will create an Item Moniker and initializes it with its left moniker
		 * and the part of the path it is supposed to represent.
		 * Typically, this method would be called with a path set to: "Sheet1" or
		 * "A2:A5".
		 * a NULL left parameter is valid provided ItemMoniker::set_left_moniker
		 * is called after.
		 */
		Moniker create_item_moniker (in Moniker left, in string path);

		/**
		 * will create a file moniker and initializes it with the path it 
		 * represents.
		 * Typically, it would be called with the path set to:
		 * "file:///home/mathieu/bidule.gnumeric.
		 */
		Moniker create_file_moniker (in string path);

	}

	/**
	 * This interface is created by calling 
	 * one of the MonikerFactory interface methods.
	 */
	interface Moniker : Object {
		exception InterfaceNotFound {
			string interface_name;
		};
	       
		exception MissingInterface {
			string interface_name;
			string object_name;
		};

		/**
		 * bind_to_object:
		 * @requested_interface: which interface we want in the end
		 *
		 * Binds a moniker. Once the service has been registered, it
		 * will attempt to get the @requester_interface
		 */
		Object bind_to_object (in string requested_interface)
			raises (InterfaceNotFound, TimeOut, MissingInterface);

		/**
		 * get_second_moniker:
		 * if you are an Item Moniker, you call left->get_second_moniker
		 * if you are a File Moniker, you return another File Moniker
		 * which is an Absolute File Moniker if the you are a relative 
		 * File Moniker. otherwise, if you are an Absolute File Moniker,
		 * this returns a relative File Moniker.
		 */
		Moniker get_second_moniker (void);


		/**
		 * get_display_name:
		 * 
		 * Returns a representation of the Moniker
		 */
		string get_display_name (void);					    
	};

	interface FileMoniker : Moniker {
	}

	interface ItemMoniker : Moniker {
		boolean set_left_moniker (in Moniker left);
	}
};


1.2) interfaces semantics
-------------------------

There are 2 levels of Linking support in applications.
Simple level
------------
	To support this, application developers must implement a
	PersistFile interface.
	This will allow users to use links of the kind:
	file:///homa/mathieu/bidule.gnumeric but not
	file:///homa/mathieu/bidule.gnumeric!Sheet1

Complex level
-------------
	To support this, application developers must implement
	the Simple Level.
	They must also implement the ParseDisplayName interface 
	and the get_object method of their Container object.

The other interfaces.
The Moniker interface must also be able to answer a QI on the
PersistStream interface.


How everything works.
	- you have a Moniker which an application pasted to you.
	to get the associated object, you call:
	moniker::bind_to_object ("Bonobo::Embeddable").
	If the moniker is a FileMoniker, it will:
	fetch the application associated to the path.
	activate this application.
	file = object->query_interface ("Bonobo::PersistFile")
	container = file->load (path);
	return container.
	If this Moniker is an ItemMoniker, it will call its 
	object = left->bind_to_object. Then, it calls 
	container = object->query_interface ("Bonobo::Container").
	new_object = container->get_object (path)
	return new_object.
	The above allows you to effectively recreate the Object 
	from the Moniker.

	- the user entered a link string and you must create the 
	corresponding moniker.
	You call MonikerFactory::parse_display_name (path)
	Now, to do this parsing, MonikerFactory will parse
	the string and create a FileMoniker from the first
	part of the string. (with file = Bonobo::create_file_moniker)
	then, app = file->bind_to_object to get the application which 
	can interpret the link.
	container = app->query_interface ("Bonobo::Container")
	then it calls: container->parse_display_name (rest_of_path).
	till this function returns a display_name_bytes_parsed == 0.
	The consecutive calls to this function will return ItemMonikers
	on which we must call first
	item_moniker->set_left_moniker (file_moniker) and then
	item_moniker->set_left_moniker (item_moniker).
	

2) API.

	Application developers who must implement linking must implement:

	- The Container::get_object method will create a GET_OBJECT signal
	which must be intercepted by the application developer to support 
	linking. This is really nice. I'd like to keep it.
	- The ParseDisplayName::parse_display_name should probably do
	the same and create PARSE_DISPLAY_NAME signal.

	- If you want to implement support for linked objects, it should 
	be easy enough:
	The BonoboMoniker object should hold 2 Moniker objects.
	(one absolute and one relative)
	bonobo_moniker_new_from_string (char **path) would allow
	you to create monikers from scratch. (easy way).
	then, you can call BonoboObject *bonobo_moniker_bind_to_object(BonoboMoniker *moniker)
	If you want to do it the hard way, you should be able to call
	straight mappings of the CORBA interfaces to C. ie:
	bonobo_moniker_factory_create_item_moniker (BonoboMoniker *left, char **path)
	bonobo_moniker_factory_create_file_moniker (char **path)
	.......

	However, app developers should be VERY stronly discouraged
	to use this API. They should use the bonobo_moniker_new_from_string
	function which will call their callbacks hooked on the GET_OBJECT and 
	PARSE_DISPLAY_NAME signals if necessary.
	The performance difference may be worth the work for _some_ applications
	but not the majority.


I hope that all this makes sense.
There is one thing on which I have not given much thoughts: it
is the exceptions. There will probably need some of them here 
and there...

Of course, I volunteer to implement this set of idl interfaces/API 
functions when people have let me known their feelings on this.


regards,
Mathieu
	



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