TWiki> Gaudi Web>UserGuide>HowToMigrateToGaudi21 (revision 1)EditAttachPDF

How-To Migrate to Gaudi v21

Introduction

This twiki page is meant to provide instructions and, to some extent, the documentation for the changes between Gaudi v19/v20 and Gaudi v21.

Interfaces

Rationale

To extend a base component with the implementation of new interfaces, we have to provide an implementation of the method IInterface::queryInterface, which is almost always the same. A typical case looks like:
class MySpecialization: public MyBase, virtual public IMyFeature {
public:
  /// Constructor
  MySpecialization();
  /// Destructor
  virtual ~MySpecialization();
  /// Implementation from IInterface
  virtual StatusCode queryInterface(const InterfaceID &riid, void **ppvInterface);
  /// Implementation from IMyFeature
  virtual StatusCode myMethod();
};
MySpecialization::MySpecialization():MyBase() {
  // ... do something
}
MySpecialization::~MySpecialization() {
  // ... do something
}
StatusCode MySpecialization::myMethod() {
  // ... do something
  return StatusCode::SUCCESS;
}
StatusCode MySpecialization::queryInterface(const InterfaceID &riid, void **ppvInterface) {
  if (ppvInterface == 0) return StatusCode::FAILURE;
  if (IMyFeature::interfaceId() == riid)  { // sometimes is IID_IMyFeature
    *ppvInterface = (IMyFeature*)this;
  }
  else  {
    return BaseClass::queryInterface(riid, ppvInterface);
  }
  addRef();
  return StatusCode::SUCCESS;
}
The implementation of queryInterface is (usually) a switch-like chain of if statements falling back on the base-class implementation. The implementation of such a method can be automated, in fact the AlgTool base class has a generic implementation based on a run-time list of implemented interfaces, so, when the base class is AlgTool, the example above becomes:
class MySpecialization: public AlgTool, virtual public IMyFeature {
public:
  /// Constructor
  MySpecialization();
  /// Destructor
  virtual ~MySpecialization();
  /// Implementation from IMyFeature
  virtual StatusCode myMethod();
};
MySpecialization::MySpecialization():AlgTool() {
  declareInterface<IMyFeature>(this);
}
MySpecialization::~MySpecialization() {
  // ... do something
}
StatusCode MySpecialization::myMethod() {
  // ... do something
  return StatusCode::SUCCESS;
}
The code for AlgTool specializations is shorter and less error-prone. The only draw-back that has not been removed is that the declaration of the implemented interfaces happens in two places: the .h file and the .cpp one, so you have to edit the two files in a consistent way.

Another limitation of the current interface implementation is that it is not possible to have interfaces extending other interfaces. It is not a technical limitation (C++ allows it, of course), but it breaks the design principles of the framework. Each interface is identified by a numerical id (usually the a hash of the name) and a version (major and minor) that allow to tell if the component that we loaded from a library is compatible with the version of the interface that we used to compile our code. When an interface inherits from another and the base interface is changed, one should modify the version numbers of the derived interface, but it is simply impossible to keep track of those kind of chains.

Using some specially crafted templated helper classes, a dedicated InterfaceId class and some "Boost::mpl" (Meta Programming Library) constructs, it is possible to make the compiler generate all the mechanical code that is needed, simplifying the maintenance of the components and allowing non-trivial interface hierarchies.

Implementation

The implementation of the new interfaces infrastructure is based on the templated classes:
implements#<...>
Used to write a class that does not have a concrete base class.
extends#<BASE, ...>
Used to write a class that inherits from a concrete base class.
extend_interfaces#<...>
Used to declare an interface that inherits from other interfaces.
Due to the absence of variadic template arguments in C++, the classes have different names depending on the number of interfaces passed as templates, e.g.:
  • implements1
  • extends2<AlgTool,ISpecial1,ISpecial2>
  • extend_interfaces1
The other key element of the new infrastructure is the preprocessor macro DeclareInterfaceID, which expands to some common code.

Interface

An interface declaration looks like:
class GAUDI_API IIncidentListener: virtual public extend_interfaces1<IInterface> {
public:
  /// InterfaceID
  DeclareInterfaceID(IIncidentListener,2,0);
  /// Inform that a new incident has occurred
  virtual void handle(const Incident&) = 0;
};
Line 1 make the interface extend IInterface (one can extend other interfaces, like INamed). Line 4 declare the interface name and version.

Component base class

class GAUDI_API Algorithm: virtual public implements3<IAlgorithm, IProperty, IStateful> {
public:
  // ... no queryInterface
};
Line 1 shows how to use the the implements#<...> helper to implements 3 interfaces.

Extension of a component

class GAUDI_API ConversionSvc: public extends2<Service, IConversionSvc, IAddressCreator> {
public:
  // ... no queryInterface
};
// Constructor
ConversionSvc::ConversionSvc(...): base_class(...) {}
The first template argument of extends#<...> is the component base class, for the rest, it works exactly as implements#<...>.

Line 6 shows how the constructor of the derived class must be written. base_class is a typedef to the actual base class (extends#<...>) that allows to avoid to repeat the list of interfaces in more than one place.

Migrating old code

Interfaces
  • The interface must be modified to inherit from extend_interfaces1 (or the version with the correct list of base interfaces).
  • We must add the call to DeclareInterfaceID in the public section, close to the declaration of the class.
  • We must remove the static function interfaceID and all the references to the IID_ static variable.
Example: IAlgorithm.
Component base class
  • Make the class inherit from implements#<...>.
  • Remove the implementation of queryInterface, addRef and release (unless non-trivial).
Extension of a component
  • Make the class inherit from extends#<...>.
  • Modify the constructor to call the constructor of base_class.
  • Remove the implementation of queryInterface, addRef and release (unless non-trivial). In case of AlgTool specializations, remove the "declareInterface" lines from the constructor.

-- MarcoClemencic - 16 Feb 2009

Edit | Attach | Watch | Print version | History: r5 | r4 < r3 < r2 < r1 | Backlinks | Raw View | Raw edit | More topic actions...
Topic revision: r1 - 2009-02-16 - MarcoClemencic
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    Gaudi All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright &© 2008-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback