If you have used CORBA before, you will see that MCOP is much the same thing. In fact, aRts prior to version 0.4 used CORBA.
The basic idea of CORBA is the same: you implement objects (components). By using the MCOP features, your objects are not only available as normal classes from the same process (via standard C++ techniques) - they also are available to remote servers transparently. For this to work, the first thing you need to do is to specify the interface of your objects in an IDL file - just like CORBA IDL. There are only a few differences.
In MCOP there are no “in” and “out” parameters on method invocations. Parameters are always incoming, the return code is always outgoing, which means that the interface:
// CORBA idl interface Account { void deposit( in long amount ); void withdraw( in long amount ); long balance(); };
is written as
// MCOP idl interface Account { void deposit( long amount ); void withdraw( long amount ); long balance(); };
in MCOP.
There is no exception support. MCOP doesn't have exceptions - it uses something else for error handling.
There are no union types and no typedefs. I don't know if that is a real weakness, something one would desperately need to survive.
There is no support for passing interfaces or object references
You declare sequences as
“sequencetype
” in MCOP. There
is no need for a typedef. For example, instead of:
// CORBA idl struct Line { long x1,y1,x2,y2; }; typedef sequence<Line> LineSeq; interface Plotter { void draw(in LineSeq lines); };
you would write
// MCOP idl struct Line { long x1,y1,x2,y2; }; interface Plotter { void draw(sequence<Line> lines); };
You can declare streams, which will then be evaluated by the aRts framework. Streams are declared in a similar manner to attributes. For example:
// MCOP idl interface Synth_ADD : SynthModule { in audio stream signal1,signal2; out audio stream outvalue; };
This says that your object will accept two incoming synchronous audio streams called signal1 and signal2. Synchronous means that these are streams that deliver x samples per second (or other time), so that the scheduler will guarantee to always provide you a balanced amount of input data (for example, 200 samples of signal1 are there and 200 samples signal2 are there). You guarantee that if your object is called with those 200 samples signal1 + signal2, it is able to produce exactly 200 samples to outvalue.
This differs from CORBA mostly:
Strings use the C++ STL string
class. When stored in sequences, they are stored “plain”,
that means they are considered to be a primitive type. Thus, they need
copying.
longs are plain long's (expected to be 32 bit).
Sequences use the C++ STL
vector
class.
Structures are all derived from the MCOP class
Type
, and generated by the MCOP IDL
compiler. When stored in sequences, they are not stored
“plain” , but as pointers, as otherwise, too much copying
would occur.
After having them passed through the IDL compiler, you need to derive
from the _skel
class. For instance, consider you
have defined your interface like this:
// MCOP idl: hello.idl interface Hello { void hello(string s); string concat(string s1, string s2); long sum2(long a, long b); };
You pass that through the IDL compiler by calling
mcopidl
, which will in turn generate
hello.idl
hello.cpp
and hello.h
. To
implement it, you need to define a C++-class that inherits the skeleton:
// C++ header file - include hello.h somewhere class Hello_impl : virtual public Hello_skel { public: void hello(const string& s); string concat(const string& s1, const string& s2); long sum2(long a, long b); };
Finally, you need to implement the methods as normal C++
// C++ implementation file // as you see string's are passed as const string references void Hello_impl::hello(const string& s) { printf("Hello '%s'!\n",s.c_str()); } // when they are a returncode they are passed as "normal" strings string Hello_impl::concat(const string& s1, const string& s2) { return s1+s2; } long Hello_impl::sum2(long a, long b) { return a+b; }
Once you do that, you have an object which can communicate using MCOP. Just create one (using the normal C++ facilities to create an object):
Hello_impl server;
And as soon as you give somebody the reference
string reference = server._toString(); printf("%s\n",reference.c_str());
and go to the MCOP idle loop
Dispatcher::the()->run();
People can access the thing using
// this code can run anywhere - not necessarily in the same process // (it may also run on a different computer/architecture) Hello *h = Hello::_fromString([the object reference printed above]);
and invoke methods:
if(h) h->hello("test"); else printf("Access failed?\n");
Would you like to comment or contribute an update to this page?
Send feedback to the TDE Development Team