[interfacekit] Phase 1

Hi,

well, it looks like I can't stop sending longish mails. ;-)

CU, Ingo


Tasks
-----

This is basically a reincarnation of the feature list I sent earlier. 
Closely related items are bundled into work packages. Though it might 
work out well, if two guys work on a package at the same time, it is 
probably simpler, if a package is dealt with by one person only.

1. BMessenger, save the signature constructor
   (LockTarget*() shouldn't be needed either, they might be easy to
   implement implement though)
2. registrar/roster embryo
   - make BApplication registrar-aware, i.e. name the looper port
     respectively
   - registrar skeleton
   - BRoster constructor/initialization
3. app registration
   - roster side registration support
   - roster side running app management
   - private BRoster app registration methods
   - basic BApplication signature constructors/BApplication::InitData()
   - BApplication::Argv/RefsReceived(), ReadyToRun(), Quit[Requested]()
4. running app querying, BMessenger
   - running application querying (roster/BRoster)
   - BMessenger: signature constructor
   - BRoster::ActivateApp()

Unfortunately the order is relatively strict: 3. requires 1. and 2., 
and 4. builds on top of 3.
1. and 2. can be done mostly in parallel, though at the end of 2. 
BMessenger will ne needed. I have no idea how well the libbe BMessenger 
deals with our BHandler/BLooper objects though.


Tests
-----

Usually I prefer to write the tests before the implementation, but I 
would relax the rule a bit. Writing the BMessenger tests first for 
instance would hold all other packages. Thus I think, it is reasonable 
to write the tests for a package after implementing it.

Originally I intended to list some test ideas for each packages, but 
it's actually straight forward: All the features implemented by a 
package need to be tested. ;-)


Conventions
-----------

A subject with a lot of potential for discussions. ;-)
I just want to propose something and, if you find it reasonable, then 
we go with it, otherwise make a proposal yourself.

First of all, the registrar is an application on its own and none of 
its code lives in libbe or appears in any of the public headers (one 
exception: _TRoster_ -- see below), so there is no reason to name 
classes BXyz and constants B_XYZ. The constants are used in the API 
classes implementations and therefore I suggest the common prefix REG_. 
The classes on the other hand don't need a prefix and thus I wouldn't 
prepend any.

For the message constant values I suggest four small letters starting 
with 'rg', e.g. 'rgsu' for REG_SUCCESS. The same convention goes for 
type constants. Note, that neither the message nor the type constants 
will ever get in touch with user application entities. Messages with a 
registrar specific "what" field or one containing a specifically typed 
field are only allowed for messages sent to the registrar and for 
synchronous reply messages to those. Such a message must never be sent 
to an application or any handler.

Error constants start at B_ERRORS_END + 1.

To not interfere with the BeOS registrar I propose the names 
"_obos_roster_thread_" and "_obos_roster_port_" for the registrar's 
main thread and app looper port respectively. The names should be 
defined as static variables in a common header file (Registrar.h). The 
other shared definitions should be located there as well.


Structures/Classes
------------------

The only more or less interesting structures/classes are those in the 
roster, namely _TRoster_ (a friend of BMessenger), which manages the 
running applications. First of all, please let us rename that beast. 
Let's move it into the BPrivate namespace and call it just Roster (or 
TRoster, though I'm not sure what the T stands for -- team maybe?).

The basic information to be stored for each application is an app_info. 
Since we need additional data to be associated with an application, we 
probably want to wrap it like this:

struct RosterAppInfo : public app_info {
        uint32          state;
        int32           argc;
        char            **argv;
        int32           ref_count;
        entry_ref       **refs;
        int32           message_count;
        BMessage        *messages;
        [...helper methods...]
};

state can be something like REG_APP_REGISTERED or REG_APP_RUNNING.
argc and argv are only needed in the registration phase, until the 
application's Run() is called and the B_ARGV_RECEIVED has been sent.
The same goes for ref_count, refs, message_count and messages, which we 
won't need until we are going to implement the respective versions of 
BRoster::Launch().

Roster must implement an efficient team_id->RosterAppInfo and signature
->set of RosterAppInfo mapping. As the number of applications will 
quite likely be relatively small (< 100), even a single unsorted list 
and a linear search should be sufficient. We may want to consider 
binary search on sorted lists or even hash tables later.

The Roster class will implement all roster features. The registrar 
application's MessageReceived() may dispatch the roster messages 
directly to the respective Roster methods. It might not even extract 
the contents of the message, but rather leave that for Roster.


Implementation
--------------

No, don't expect to find the complete implementation in this section.
;-)

Just a short implementation remark concerning the app registration. 
Until this time I don't see the need for all the private BRoster 
registration related methods. I would keep only four of them and change 
there semantics a bit:

status_t RegisterApp(const char *signature, const entry_ref *ref
                                         uint32 flags, team_id team, port_id 
port,
                                         int32 argc, const char *const *argv)

Registers the application with the roster. Called from the BApplication 
constructor. It fails when the application is single/exclusive launch 
and an instance of it is already running. The supplied command line 
arguments are sent (by the roster) as a B_ARGV_RECEIVED message to the 
respective team in this case.

params:
- signature: The application signature.
- ref: An entry_ref to the application executable.
- flags: The application flags.
- team: The application team.
- port: The app looper port.
- argc: The application's command line parameter count.
- argv: The application's command line parameters.

return:
- B_OK: :-))
- B_BAD_VALUE: Invalid parameter value.
- REG_ALREADY_REGISTERED: For single/exclusive launch applications
  that are launched the second time.
- ...

-----------------------------------------------------------------------

status_t RegisterRunningApp(team_id team, thread_id thread)

Tells the roster, that the application is now going to run the message 
loop. The roster sends the command line arguments as a B_ARGV_RECEIVED 
message and if applicable also a B_REFS_RECEIVED and other initial 
messages and finally a B_READY_TO_RUN.

params:
- team: The application team.
- thread: The application looper thread.

return:
- B_OK: :-))
- ...

-----------------------------------------------------------------------

status_t UnregisterRunningApp(team_id team)

Tells the roster, that the application is going to stop the message 
loop.

params:
- team: The application team.

return:
- B_OK: :-))
- ...

-----------------------------------------------------------------------

status_t UnregisterApp(team_id team)

Unregisters the application from the roster. Called from the 
BApplication destructor.

params:
- team: The application team.

return:
- B_OK: :-))
- ...


Protocols
---------

standard success reply message

reply:          - REG_SUCCESS
                          [ <additional fields> ]

fields:
- <additional fields>: Request-specific fields.

-----------------------------------------------------------------------

standard error reply message

reply:          - REG_ERROR
                          "error": B_INT32_TYPE
                          [ "error_description": B_STRING_TYPE ]
                          [ <additional fields> ]

fields:
- "error": The error code (a status_t).
- "error_description": Optional human readable description.
- <additional fields>: Request-specific fields.

-----------------------------------------------------------------------

(package 2)

getting the messengers for MIME and clipboard management respectively

target:         registrar app looper (preferred handler)
message:        REG_GET_MIME_MESSENGER/REG_GET_CLIPBOARD_MESSENGER
reply:          standard success
                        "messenger": B_MESSENGER_TYPE
on error:       - B_NO_REPLY (fatal)
                        - standard error (fatal)

reply fields:
- "messenger": The requested messenger.

-----------------------------------------------------------------------

(package 3)

app registration (BRoster::RegisterApp())

target:         roster
message:        REG_REGISTER_APP
                        "signature": B_MIME_STRING_TYPE
                        "ref": B_REF_TYPE
                        "flags": B_UINT32_TYPE
                        "team": B_INT32_TYPE
                        "port": B_INT32_TYPE
                        "argv": B_STRING_TYPE[]
reply:          standard success
on error:       - B_NO_REPLY (fatal)
                        - standard error

message fields:
- "signature": The application signature.
- "ref": An entry_ref to the application executable.
- "flags": The application flags.
- "team": The application team (team_id).
- "port": The app looper port (port_id).
- "argv": The application's command line parameters.

error reply fields:
- "error":
  - B_BAD_VALUE: A request message field is missing or contains an
    invalid value.
  - REG_ALREADY_REGISTERED: For single/exclusive launch applications
    that are launched the second time.
  - ...

-----------------------------------------------------------------------

app registration (BRoster::RegisterRunningApp())

target:         roster
message:        REG_REGISTER_RUNNING_APP
                        "team": B_INT32_TYPE
                        "thread": B_INT32_TYPE
reply:          standard success
on error:       - B_NO_REPLY (fatal)
                        - standard error (fatal)

message fields:
- "team": The application team (team_id).
- "thread": The application looper thread (thread_id).

-----------------------------------------------------------------------

app unregistration (BRoster::UnregisterRunningApp())

target:         roster
message:        REG_UNREGISTER_RUNNING_APP
                        "team": B_INT32_TYPE
reply:          standard success
on error:       - B_NO_REPLY (fatal)
                        - standard error (fatal)

message fields:
- "team": The application team (team_id).

-----------------------------------------------------------------------

app unregistration (BRoster::UnregisterApp())

target:         roster
message:        REG_UNREGISTER_APP
                        "team": B_INT32_TYPE
reply:          standard success
on error:       - B_NO_REPLY (fatal)
                        - standard error (fatal)

message fields:
- "team": The application team (team_id).

-----------------------------------------------------------------------

(package 4)

getting a running app list (BRoster::GetAppList())

target:         roster
message:        REG_GET_APP_LIST
                        [ "signature": B_MIME_STRING_TYPE ]
reply:          standard success
                        [ "teams": B_INT32_TYPE[] ]
on error:       - B_NO_REPLY (fatal)
                        - standard error (fatal)

message fields:
- "signature": The signature of the running applications to be listed.
                           All running applications, if omitted.

reply fields:
- "teams": The team IDs of the applications found (team_id). Omitted,
                   if no application could be found.

-----------------------------------------------------------------------

getting a running app info (BRoster::GetRunningAppInfo(), 
BRoster::GetActiveAppInfo())

target:         roster
message:        REG_GET_RUNNING_APP_INFO
                        [ "team": B_INT32_TYPE ]
reply:          standard success
                        "info": REG_APP_INFO_TYPE
on error:       - B_NO_REPLY (fatal)
                        - standard error

message fields:
- "team": The team ID of the application in question (team_id).
                  If omitted, the active application is considered.

reply fields:
- "info": An app_info structure containing the requested info.

error reply fields:
- "error":
  - B_BAD_TEAM_ID: No team with the supplied ID exists.
  - B_ENTRY_NOT_FOUND: The supplied team ID does not identify an
    application (the team exists though), or currently there is no
        active application.
  - ...

-----------------------------------------------------------------------

app activation (BRoster::ActivateApp())

target:         roster
message:        REG_ACTIVATE_APP
                        "team": B_INT32_TYPE
reply:          standard success
on error:       - B_NO_REPLY (fatal)
                        - standard error

message fields:
- "team": The team ID of the application to be activated.

error reply fields:
- "error":
  - B_BAD_TEAM_ID: No team with the supplied ID exists.
  - B_ENTRY_NOT_FOUND: The supplied team ID does not identify an
    application (the team exists though).
  - ...





Other related posts: