With the availability of industrial strength distributed object technology such as Orbix/CORBA, it seems natural to extend hush with the functionality needed to develop distributed CORBA-based hush components.
However, extending a given framework is not as straightforward as it may seem. First of all, one has to decide which interfaces may become public, that is may be exported as IDL interfaces. Secondly, one has to decide how object references become known to clients, and what rights clients have to create objects within a particular server. The most important problem, however, concerns the type clash between the CORBA classes implementing the IDL interfaces and the 'native' class hierarchy offered by the framework itself.
This paper gives an overview of the effort of extending hush with CORBA. In section 2, the various issues involved in extending a given framework or toolkit will be discussed in somewhat more detail. In section 3, the IDL interfaces for hush and the widgets will be described. In section 4, some examples are given of how to use hush in a CORBA environment. Finally, in section 5, we will discuss what further research is needed to make hush fully 'CORBA-compliant'.
For giving access to objects within a particular hush component, we have provided dots (distributed object tables) for both hush and widgets components. Using the dot the client can access an object of a given type by the name it is given by the server. The object must already exist in the server.
In case clients are allowed to create objects within the server, a factory is provided for creating hush or widget objects.
To allow clients the use of CORBA IDL classes wherever one of the original hush classes is expected, client-side adaptors have been provided for each of the hush or widgets IDL classes. An additional advantage of client-side adpators is that they allow for overcoming the 'weaknesses' of IDL with respect to overloading member functions, parametrized types and operator definitions.
Typically, client-side adaptors have their corresponding hush class as a base class and simply delegate method invocations to the CORBA object they encapsulate.
Nevertheless, in our opinion events should be used in a very restricted manner. Events tend to break the 'crisp' object interfaces that are one of the benefits of an object-oriented approach to design.
For the hush CORBA extensions, we have chosen for retaining the original hush object interfaces. Note however that the IDL interfaces are somewhat more abstract than the corresponding C++ interfaces. Nevertheless, the event interface is part of the hush module. Together with the dispatch function of the handler interface incoming events resulting from user actions may be dispatched directly to remote components. See the Canvas example.
interface handler {
event dispatch( in event data );
};
interface event : handler {
attribute long type;
attribute long x;
attribute long y;
};
interface kit : handler {
void source(in string file);
void eval(in string command);
term result();
widget root();
};
interface widget : handler {
string path();
void eval( in string cmd );
void configure( in string options );
void pack( in string options );
};
interface item : handler {
void move( in long x, in long y );
};
interface iterator {
Object next();
};
interface container {
long length();
Object first();
Object next();
Object current();
iterator walk();
};
interface term {
string next();
};
interface factory {
hush::kit kit(in string name);
hush::event event(in long type);
};
interface dot {
hush::kit kit(in string name);
hush::container container(in string name);
hush::iterator iterator(in string name);
hush::factory hush(in string name);
};
module widgets {
interface canvas : hush::widget {
widgets::canvas create( in hush::widget anc, in string path );
hush::item circle( in long x, in long y, in long radius, in string options );
// other items ...
};
interface message : hush::widget {
message create( in hush::widget anc, in string path );
void text(in string txt);
};
interface factory : hush::factory {
widgets::canvas canvas(in string name, in string options);
widgets::message message(in string name, in string options);
};
interface dot : hush::dot {
widgets::canvas canvas(in string name);
widgets::message message(in string name);
widgets::factory widgets(in string name);
};
};
hush::dot* hush; // (distributed) object tables
widgets::dot* widgets; // widgets contains hush
hush::kit* tk; // remote objects, these must exist!
widgets::message* banner;
try {
hush = widgets = widgets::dot::_bind (DOT, argv[1]);
tk = hush->kit("tk");
banner = widgets->message("hello"); // must exist
} catch (...) {
cerr << "Unexpected exception ..." << endl;
return -1;
}
while (1) {
char text = readtext(); // from stdin
banner->text( text ); // display text
tk->eval(text);
}
class application : public session {
public:
application(int argc, char* argv[]) : session(argc,argv,"hello") {
}
void corba();
int main() {
tk->trace();
kit::declare("tk",tk);
message* m = new hello(".hello");
m->pack();
message::declare("hello",m);
corba(); // make yourself available as a server
return OK;
}
};
void application::corba() {
widgets::dot* dw = new widgets_dot_srv(); // create dot for widgets
try {
CORBA::Orbix.registerIOCallback(it_orbix_fd_open, FD_OPEN_CALLBACK);
CORBA::Orbix.registerIOCallback(it_orbix_fd_close, FD_CLOSE_CALLBACK);
CORBA::Orbix.impl_is_ready(DOT,0);
CORBA::Orbix.processEvents(0);
}
catch (...) {
cout << "apparently something went wrong" << endl;
}
try {
tk = hush->kit("bp"); // A kit for BinProlog
tk->eval("consult(facts)");
}
catch(...) {
cout << "An exception ... " << endl;
}
while (1) {
char* text = readtext();
tk->eval(text);
hush::term* t = tk->result();
char* q = 0;
while ( (q = t->next()) )
cout << "Result: " << q << endl;
}
class draw_clt : public canvas { [2]
public:
void plug(widgets::canvas* x) { draw = x; }
int operator()() {
hush::event* e = hush->event(_event->type());
cerr << "Getting event " << e->type() << endl;
e->x(_event->x()+10);
e->y(_event->y()+10);
//hush::event::_duplicate(e); // CORBA 2.0
e->_duplicate();
hush::event* res = draw->dispatch(e);
return canvas::operator()();
}
draw_clt(const widget* w, char* path ) : canvas(w,path) {
configure("-background white");
geometry(200,100);
self()->bind(this);
dragging = 0;
}
draw_clt(char* path ) : canvas(path) {
configure("-background white");
geometry(200,100);
self()->bind(this);
dragging = 0;
}
void press( event& ) { dragging = 1; }
void motion( event& e) {
if (dragging) {
self()->circle(e.x(),e.y(),2,"-fill black");
draw->circle(e.x(),e.y(),3,"-fill yellow");
}
}
void release( event& ) { dragging = 0; }
protected:
int dragging;
widgets::canvas* draw;
};
class draw_srv : public canvas {
public:
draw_srv( const widget* w, char* path ) : canvas(w,path) { (a)
geometry(200,100);
self()->bind(this);
dragging = 0;
}
void press( event& ) { dragging = 1; }
void motion( event& e) {
if (dragging) circle(e.x(),e.y(),10,"-fill black");
}
void release( event& ) { dragging = 0; }
protected:
int dragging;
};
list<hush::item>* rlist = new list<hush::item>;
item* it = draw->circle(40,40,10,"-fill yellow");
hush::item* rit = new item_srv(it);
rlist->insert(rit);
it = draw->circle(30,30,10,"-fill red");
rit = new item_srv(it);
rlist->insert(rit);
hush::container* rx = new list_srv<hush::item>(rlist);
list<hush::item>::declare("items",rx); // store server
iter<hush::item>* riter = rlist->walk();
iter<hush::item>::declare("riter",riter);
Evidently, the contribution of this work is that it shows how to integrate CORBA functionality with an already existing framework. In particular the need for client-side adaptors for resolving the type clash between the 'native' classes and the CORBA IDL classes has been amply demonstrated. Enriching hush with CORBA makes crush a potential competitor of Fresco, the CORBA based GUI toolkit derived from the Interviews library.
#ifndef _orb_common_h #define _orb_common_h #ifndef ENV #define ENV CORBA::Environment& #endif #ifndef _sk #define _sk(X) X##BOAImpl #endif #ifndef _msk #define _msk(M,X) M::_sk(X) #endif #ifndef _crob #define _crob(M,X) public virtual _msk(M,X) #endif #endif
class handler_srv : _crob(hush,handler) {
public:
handler_srv(const handler* x = 0) : _bdy((handler*)x) { }
protected:
void set_body(const handler* x) { _bdy = (handler*) x; }
handler* _body() const {
return (handler*) _bdy;
}
virtual hush::event* dispatch(hush::event* e, ENV);
private:
handler* _bdy;
};
class handler_clt : public handler {
protected:
handler_clt(handler_srv* x) : _bdy(x) { }
void set_body(void* x) { _bdy = x; }
handler* _body() {
if (!_bdy) throw "handler has no body";
return (handler*) _bdy;
}
private:
void* _bdy;
};
class event_srv : public handler_srv, _crob(hush,event) {
public:
event_srv(event* e) : handler_srv(e) { }
event_srv() { _type = 0; _x = 0; _y = 0; }
virtual void type( long t, ENV ) { _type = t; }
virtual long type( ENV ) { return _type; }
virtual void x( long t, ENV ) { _x = t; }
virtual long x( ENV ) { return _x; }
virtual void y( long t, ENV ) { _y = t; }
virtual long y( ENV ) { return _y; }
protected:
event* _body() { return (event*) handler_srv::_body(); }
long _type, _x, _y;
};
class event_clt : public event {
public:
event_clt(hush::event* x) : _bdy(x), event(this) { }
hush::event* operator->() { return _body(); }
virtual int type() const { return (int) _body()->type(); }
virtual int x() const { return (int) _body()->x(); }
virtual int y() const { return (int) _body()->y(); }
virtual void type(int n) { _body()->type( (long) n ); }
virtual void x(int n) { _body()->x( (long) n ); }
virtual void y(int n) { _body()->y( (long) n ); }
/* Orbix 2.0
virtual void type(int n) { _body()->type( (CORBA::Long) n ); }
virtual void x(int n) { _body()->x( (CORBA::Long) n ); }
virtual void y(int n) { _body()->y( (CORBA::Long) n ); }
*/
private:
void* _bdy;
hush::event* _body() const { return (hush::event*) _bdy; }
};
class kit_srv : public handler_srv, _crob(hush,kit) {
public:
kit_srv(kit* tk) : handler_srv(tk) { }
virtual void source( const char* s, ENV ) {
char* p = new char[strlen(s)+1]; strcpy(p,s);
_body()->source(p);
}
virtual void eval( const char* s, ENV ) {
_body()->eval(s);
}
virtual hush::term* result( ENV ) {
term* x = (term*) _body()->result();
hush::term* res = new term_srv(x);
res->_duplicate(); // orbix 1.3
return res;
}
virtual void update( ENV ) { _body()->update(); }
virtual hush::widget* root( ENV );
protected:
kit* _body() { return (kit*) handler_srv::_body(); }
};
class kit_clt : public kit {
public:
kit_clt(hush::kit* x) : _bdy(x) { }
virtual int eval( const char* s ) { _body()->eval(s); return 0; }
virtual widget* root( ) const;
private:
void* _bdy;
hush::kit* _body() const { return (hush::kit*) _bdy; }
};
template<class T>
class list_srv : _crob(hush,container) {
public:
list_srv(list<T>* it = 0) : _bdy(it) {
this->_duplicate();
}
hush::iterator* walk( ENV ) {
iter<void>* it = ((list<void>*) _body())->walk();
iter_srv* x = new iter_srv(it);
x->_duplicate();
return x;
}
long length( ENV ) {
return (long) _body()->length();
}
CORBA::Object* first( ENV ) {
T* x = _body()->first();
//dummy->_duplicate(x); // Orbix 2.0
x->_duplicate();
return x;
}
CORBA::Object* current( ENV ) {
T* x = _body()->current();
x->_duplicate();
return x;
}
CORBA::Object* next( ENV ) {
T* x = _body()->next();
x->_duplicate();
return x;
}
protected:
T* dummy; // for duplication in 2.0
list<T>* _bdy;
list<T>* _body() const { return (list<T>*) _bdy; }
};
template<class T>
class list_clt : public list<T> {
public:
list_clt(hush::container* it = 0, T* = 0) : _bdy(it) { }
list_clt<T>* operator->() { return this; }
void operator=(hush::container* it) { _bdy = it; }
T* first() {
CORBA::Object* x = _body()->first();
if (x)
return (T*) dummy->_narrow(x);
else return 0;
}
T* next() {
CORBA::Object* x = _body()->next();
if (x)
return (T*) dummy->_narrow(x);
else return 0;
}
protected:
hush::container* _bdy;
hush::container* _body() const { return (hush::container*) _bdy; }
private:
static T* dummy;
};
};
class iter_srv : _crob(hush,iterator) {
public:
iter_srv(void* it) : _bdy(it) { }
CORBA::Object* next( ENV ) {
return _body()->operator()();
}
protected:
void* _bdy;
iter<CORBA::Object>* _body() const { return (iter<CORBA::Object>*) _bdy; }
};
class iter_clt : public iter<T> {
public:
iter_clt(hush::iterator* it = 0, T* = 0) : _bdy(it) { }
hush::iterator* operator->() { return _body(); }
void operator=(hush::iterator* it) { _bdy = it; }
T* operator()() {
CORBA::Object* x = _body()->next();
if (x)
return (T*) dummy._narrow(x);
else return 0;
}
protected:
hush::iterator* _bdy;
hush::iterator* _body() const { return (hush::iterator*) _bdy; }
private:
static T dummy;
};
|
Hush Online Technology
hush@cs.vu.nl
11/25/99 |
|
|