2005/5/10

     
 

ACDK DMI Server Objects

artefaktur

| DMI Basics | Features Profile | DMI Client Interface | ScriptVar | DMI Server | Using DMI in C++ | DMI with CfgScript | DMI Server Objects | Subclassing | Delegates |


How to implement own Objects, which can be called via DMI clients.


Content of this chapter:

   Standard ACDK C++-Objects
     Sample C++ Object
     Valid DMI-able Types
     Executing acdmc
     Adding the basic Metainfo to the shared libary/executable
     Adding the extended Metainfo to the shared libary/executable
     Create a separate extended Metainfo shared library
   Derive from classes with Metainfo
   Underlying structures for DMI
   DMI Interface to scripting Objects



 Standard ACDK C++-Objects

The sources of DMI-able ACDK C++-Object are normal C++ classes with following conditions:
  • Classes has to be derived from the ACDK class acdk::lang::Object or from ::acdk::lang::InterfaceBase (using ACDK_INTERFACEBASE)
  • Sources can contain C++ code, which is not part of of the ACDK DMI type system.
  • ACDK classes can contain super classes, functions, members which are not part of the ACDK DMI type system but they should have the 'foreign' attribute to avoid errors/warnings from the acdkmc meta compiler.
  • The directory structure of the sources should reflect the namespaces: The directory ./src/com/company should contain classes in the namespace com::company.
  • The name of the shared library should reflect the contained namespaces (or part of it). See also  ClassLoader.
  • In one package/shared library namespace parts should be unambiguously to avoid problems with linker.
  • In each directory/namespace an header with the same name of the right part of the namespace should be created.
    ./src/com/company/company.h. This header should contain includes, which needed before other includes.
  • Although not really required, it is strongly recommended to keep the naming style guides (namespace with all lower case letters, classes with first upper case letter).

 Sample C++ Object



#ifndef com_company_MyClass_h
#define com_company_MyClass_h

#include <acdk.h> // common header
#include "Config.h" // defines dll export macro 
                    // see Config.h's in standard acdk package
#include "company.h" // standard includes for this namespace
                     // may be empty but needed for acdkmc

namespace com {
namespace company {


// forward declaration of MyClass, RMyClass, 
// MyClassArray, RMyClassArray
ACDK_DECL_CLASS(MyClass); 

class ACDK_COM_COMPANY_PUBLIC /* defined in Config.h */ MyClass
: extends acdk::lang::Object // has to derived indirect or direct from Object
, implements acdk::lang::Comparable 
{
  ACDK_WITH_METAINFO(MyClass) // standard dmi interface
                              // mc generates meta info for this class
protected:
public: 
  // used by ClassLoader (Class::forName("com/company/MyClass")->newInstance())
  // If Extended Metainfo is available, this method is superflous, because the
  // ClassLoader also can use the public no-args constructor.
  static RObject create_instance() { new MyClass(); }
  
  foreign int internal_val; // foreign tags type, method or member as unknown to meta compiler
  int ival; // availabe via peek/poke
  static RString sval // available via static_peek/static_poke
  foreign const char* internal_ptr; // meta compiler always ignore unknown
                                    // types, foreign avoids waring of acdkmc
  MyClass();
  RString foo(int i); // available via DMI invoke
  int operator+(IN(RString) s); // available via dmi (invoke("operator_pl", mystr))
  
  // the method compareTo is implemented for the Comparable 
  // interface. This can be tagged as foreign, because a valid
  // DMI proxy for this method is already provided by the 
  // Comparable interface.
  foreign int compareTo(IN(RObject) o); 
};
#endif //com_company_MyClass_h


 Valid DMI-able Types

  • Basic types:
    • void
    • bool
    • char (1 byte character)
    • uc2char (2 byte unicode character)
    • uc4char (4 byte unicode character)
    • byte (it is unsigned char)
    • short (16 bit signed short)
    • int (32 bit signed integer)
    • jlong (64 bit signed integer)
    • float (32 bit float)
    • double (64 bit float)

  • Enumerations, which are declared (not necessary defined) in the same header.
  • Reference type to ACDK classes.

Addionally the types can have additionally attributes:
IN(type), OUT(type), INOUT(type), BYVAL(type).

See also:  Types.

 Executing acdmc

!

The meta compiler acdkmc should always executed with a directory as argument, to generate Metainfo for all header of one namespace/directory.
 acdkmc collects all meta information in 2 C++ source files.
// files
./src/com/company/MyClass.h
./src/com/company/MyClass.cpp
$ACDKHOME/bin/acdkmc src/com/company
This will generate additionally files:
./src/com/company/company_metainf_base.cpp

./src/com/company/company_metainf/company_metainf_ext.cpp

See also:  man acdkmc.

!

On windows platforms the metacompiler may also be named acdkmc_d.exe or acdkmc_r.exe for debug/release version.

 Adding the basic Metainfo to the shared libary/executable


In case of many ACDK classes ./src/com/company directory the *_metainf_ext.cpp files will split into multiple files.

The *_metainf_base.cpp has to be linked into the same shared library or executable as the original C++ classes. It contains the core class definitions of the ACDK Objects. They are used by the acdk ClassLoader, the garbage collecting routines and in some situations (arrays) for gathering information about derivation.

 Adding the extended Metainfo to the shared libary/executable

The *_metainf_ext.cpp
contains the DMI stubs.
In case the ACDK Objects mainly should be used via DMI and/or the library only contains a few ACDK DMI Objects this sources can be linked directly into the library/executable of the C++ classes.

 Create a separate extended Metainfo shared library

It is also possible to link all *_metainf_ext.cpp files into a separate shared library. In this case the name of the shared library has to follow the rules:
  • The library name must be the fully qualified name (namespace and class name) or left side parts of of the fully qualified name.
  • this name must be appended with _metainf
  • The shared library has to stored in the $ACDKHOME/bin directory.

For our example above valid shared library names are:
- libcom_company_MyClass_metainf.so (unix)
- com_company_MyClass_metainf_d.dll (windows debug version)
- com_company_MyClass_metainf_r.dll (windows release version)
- libcom_company_metainf.so (unix)
- com_company_metainf_d.dll (windows debug version)
- com_company_metainf_r.dll (windows release version)

In this case the *_metainf[.so|.dll] will be automatically loaded by the class loader if an object will be addressed via DMI.

See also:  ClassLoader.




 Derive from classes with Metainfo

ACDK C++ classes can be derived from ACDK C++ classes with Metainfo without define itself Metainfo.

It is possible to write ACDK classes without ACDK_WITH_METAINFO.

class MyClass : extends acdk::lang::Object { // no ACDK_WITH_METAINFO ...
};
But there are some limits:

If you derive your class from a class and a interface the static methods clazzInfo(); and GetClass() cannot be resolved correctly. Therefore you can use the Macro DECL_ACDK_DEFAULT_METACLASS().

ACDK_DECL_CLASS(MySpecialMap);

class MySpecialMap
: extends acdk::lang::Object
, implements acdk::util::Map
{
// if requested meta info, use the meta info from acdk::util::Map
// GetClass does return the Class from Map.
  DECL_ACDK_DEFAULT_METACLASS(Map) 
public:
// 
};

Another conflict situation is if a class with meta info uses another class without meta info:

// class without meta info
ACDK_DECL_CLASS(PureClass);

ACDK_DECL_CLASS(ClassWithMeta);

class ClassWithMeta
: extends Object
{
  ACDK_WITH_METAINFO(ClassWithMeta);
public:
  // ...
  foreign RPureClass myMember;
  foreign void setPClass(IN(RPureClass) other);
};
If in a class with Metainfo fields, argument or return types are used, with itself has no Metainfo, these fields/methods has to be marked with the pseudo keyword foreign. For these fields/methods no Metainfo will be generated.


 Underlying structures for DMI

ACDK uses C structures containing detailed information of a class with its member and function with detailed argument types.
The structures are defined in acdk_core/src/acdk/lang/dmi/ClazzInfo.h (see also  acdk::lang::dmi::ClazzInfo).

Additionally interfaces for dynamic invocations are defined in acdk_core/src/acdk/lang/dmi/StdDispatch.h.

See also:


 DMI Interface to scripting Objects

The DMI interface is not only used to make C++ Objects available to various scripting languages and component architectures, but it is also used to enable foreign object/components to any other DMI clients.

To enable foreign object to be callable via DMI normally an Proxy-Class for such an foreign Object will be implemented into ACDK C++. For example  acdk::perl::PerlObject is an DMI able Object for all Perl classes. acdk::java::JavaObject is a wrapper to Java objects ( acdk::java::JavaObject),  acdkx::com::ComObject is a Proxy for COM-Objects.
Each these Proxy classes forwards an obj->invoke("methodName") to the underlying object. The implementation of these proxy classes does not implement the invoke(), peek(), etc. but a few methods defined in  acdk::lang::dmi::StdDispatch.

Extended features, like a ClassLoader and script implemented interfaces is provided by the  CfgScript language.