libSBML Python API  5.20.2
Loading...
Searching...
No Matches
doc_extension_sbmlextension Class Reference

Detailed Description

Each package implementation must contain a class that extends SBMLExtension. For example, the class GroupsExtension serves this purpose for the SBML Level 3 Groups package extension in libSBML. The following subsections detail the basic steps involved in implementing such an extended class.

1. Define the getPackageName() method

Define a method named getPackageName() that returns the name of the package as a string. The following is an example from the implementation of the Groups package extension:

const std::string& GroupsExtension::getPackageName ()
{
static const std::string pkgName = "groups";
return pkgName;
}

2. Define methods returning package version information

Define a set of methods that return the default SBML Level, SBML Version and version of the package. These methods must be named getDefaultLevel(), getDefaultVersion() and getDefaultPackageVersion(), respectively. The following are examples drawn from the Groups package implementation:

unsigned int GroupsExtension::getDefaultLevel()
{
return 3;
}
unsigned int GroupsExtension::getDefaultVersion()
{
return 1;
}
unsigned int GroupsExtension::getDefaultPackageVersion()
{
return 1;
}

3. Define methods returning the package namespace URIs

Define methods that return strings representing the XML namespace URI for the package. One method should be defined for each SBML Level/Version combination for which the package can be used. For instance, if a package is only usable in SBML Level 3 Version 1, and the libSBML extension for the package implements version 1 of the package, the necessary method is getXmlnsL3V1V1().

const std::string& GroupsExtension::getXmlnsL3V1V1 ()
{
static const std::string xmlns = "http://www.sbml.org/sbml/level3/version1/groups/version1";
return xmlns;
}

Define other similar methods to return additional namespace URIs if the package extension implements other package versions or supports other SBML Level/Version combinations.

4. Override basic pure virtual methods

Override the following pure virtual methods on SBMLExtension:

  • virtual const std::string& getName() const =0. This method returns the nickname of the package (e.g., "layout", "groups").
  • virtual unsigned int getLevel(const std::string& uri) const =0. This method returns the SBML Level with the given URI of this package.
  • virtual unsigned int getVersion(const std::string& uri) const =0. This method returns the SBML Version with the given URI of this package.
  • virtual unsigned int getPackageVersion(const std::string &uri) const =0. This method returns the package version with the given URI of this package.
  • virtual unsigned int getURI(unsigned int sbmlLevel, unsigned int sbmlVersion, unsigned int pkgVersion) const =0. This method returns the URI (namespace) of the package corresponding to the combination of the given SBML Level, SBML Version, and package version
  • virtual SBMLExtension* clone() const = 0. This method creates and returns a deep copy of this derived object.

As an example, the following are the versions of these methods for the Groups package:

const std::string& GroupsExtension::getName() const
{
return getPackageName();
}
unsigned int GroupsExtension::getLevel(const std::string& uri) const
{
if (uri == getXmlnsL3V1V1())
return 3;
else
return 0;
}
unsigned int GroupsExtension::getVersion(const std::string& uri) const
{
if (uri == getXmlnsL3V1V1())
return 1;
else
return 0;
}
unsigned int GroupsExtension::getPackageVersion(const std::string& uri) const
{
if (uri == getXmlnsL3V1V1())
return 1;
else
return 0;
}
const std::string& GroupsExtension::getURI(unsigned int sbmlLevel,
unsigned int sbmlVersion,
unsigned int pkgVersion) const
{
if (sbmlLevel == 3 && sbmlVersion == 1 && pkgVersion == 1)
return getXmlnsL3V1V1();
static std::string empty = "";
return empty;
}
GroupsExtension* GroupsExtension::clone() const
{
return new GroupsExtension(*this);
}

Constructor, copy constructor, and destructor methods also must be overridden if additional data members are defined in the derived class.

5. Create SBMLExtensionNamespaces-related definitions

Define typedef and template instantiation code for a package-specific subclass of the SBMLExtensionNamespaces template class. The SBMLExtensionNamespaces template class is a derived class of SBMLNamespaces and can be used as an argument of constructors of SBase-derived classes defined in the package extensions.

  1. Define a typedef. For example, the typedef for GroupsExtension is implemented in the file GroupsExtension.h as follows:

    // GroupsPkgNamespaces is derived from the SBMLNamespaces class.
    // It is used when creating a Groups package object of a class
    // derived from SBase.
    typedef SBMLExtensionNamespaces<GroupsExtension> GroupsPkgNamespaces;

  2. Define a template instantiation for the typedef. For example, the template instantiation code for GroupsExtension is implemented in the file GroupsExtension.cpp as follows:

    template class LIBSBML_EXTERN SBMLExtensionNamespaces<GroupsExtension>;

Here is example of how the resulting class is used. The definitions above allow a GroupsPkgNamespaces object to be used when creating a new Group object. The GroupsPkgNamespaces is handed to the constructor as an argument, as shown below:

GroupPkgNamespaces gpns(3, 1, 1); // SBML Level, Version, & pkg version.
Group g = new Group(&gpns); // Creates a Group object.

The GroupsPkgNamespaces object can also be used when creating an SBMLDocument object with the Groups package. The code fragment below shows an example of this:

GroupsPkgNamespaces gpns(3, 1, 1);
SBMLDocument* doc;
doc = new SBMLDocument(&gnps);

6. Override the method getSBMLExtensionNamespaces()

Override the pure virtual method getSBMLExtensionNamespaces(), which returns an SBMLNamespaces derived object. For example, the method is overridden in the class GroupsExtension as follows:

SBMLNamespaces*
GroupsExtension::getSBMLExtensionNamespaces(const std::string& uri) const
{
GroupsPkgNamespaces* pkgns = NULL;
if ( uri == getXmlnsL3V1V1())
{
pkgns = new GroupsPkgNamespaces(3, 1, 1);
}
return pkgns;
}

7. Define an enumeration for the package object type codes

Define an enum type for representing the type code of the objects defined in the package extension. For example, the enumeration SBMLGroupsTypeCode_t for the Groups package is defined in GroupsExtension.h as follows:

typedef enum
{
SBML_GROUPS_GROUP = 500
, SBML_GROUPS_MEMBER = 501
} SBMLGroupsTypeCode_t;

In the enumeration above, SBML_GROUPS_GROUP corresponds to the Group class (for the <group> element defined by the SBML Level 3 Groups package) and SBML_GROUPS_MEMBER corresponds to the Member class (for the <member> element defined by the Level 3 Groups package), respectively.

Similarly, #SBMLLayoutTypeCode_t for the Layout package is defined in the file LayoutExtension.h as follows:

typedef enum
{
SBML_LAYOUT_BOUNDINGBOX = 100
, SBML_LAYOUT_COMPARTMENTGLYPH = 101
, SBML_LAYOUT_CUBICBEZIER = 102
, SBML_LAYOUT_CURVE = 103
, SBML_LAYOUT_DIMENSIONS = 104
, SBML_LAYOUT_GRAPHICALOBJECT = 105
, SBML_LAYOUT_LAYOUT = 106
, SBML_LAYOUT_LINESEGMENT = 107
, SBML_LAYOUT_POINT = 108
, SBML_LAYOUT_REACTIONGLYPH = 109
, SBML_LAYOUT_SPECIESGLYPH = 110
, SBML_LAYOUT_SPECIESREFERENCEGLYPH = 111
, SBML_LAYOUT_TEXTGLYPH = 112
} SBMLLayoutTypeCode_t;

These enum values are returned by corresponding getTypeCode() methods. (E.g., SBML_GROUPS_GROUP is returned in Group::getTypeCode().)

Note that libSBML does not require that type codes are unique across all packages—the same type codes may be used within individual package extensions. LibSBML development must permit this because package implementations are developed by separate groups at different times; coordinating the type codes used is impractical. It does mean that callers must check two things when identifying objects: to distinguish the type codes of different packages, callers much check not only the return value of the method getTypeCode() method but also that of the method getPackageName(). Here is an example of doing that:

void example (const SBase *sb)
{
const std::string pkgName = sb->getPackageName();
if (pkgName == "core") {
switch (sb->getTypeCode()) {
case SBML_MODEL:
....
break;
case SBML_REACTION:
....
}
}
else if (pkgName == "layout") {
switch (sb->getTypeCode()) {
....
break;
....
}
}
else if (pkgName == "groups") {
switch (sb->getTypeCode()) {
....
break;
....
}
}
...
}
SBML_GROUPS_MEMBER
long
Definition libsbml.py:7464
SBML_LAYOUT_REACTIONGLYPH
layout One of the possible SBML component type codes.
Definition libsbml.py:7750
SBML_GROUPS_GROUP
groups One of the possible SBML component type codes.
Definition libsbml.py:7485
SBML_LAYOUT_LAYOUT
layout One of the possible SBML component type codes.
Definition libsbml.py:7681

Readers may have noticed that in the #SBMLLayoutTypeCode_t and SBMLGroupsTypeCode_t enumerations above, unique values are in fact assigned to the enumeration values. This can be convenient when it can be arranged, but it is not required by libSBML.

8. Override the method getStringFromTypeCode()

Override the pure virtual method getStringFromTypeCode(), which returns a string corresponding to the given type code. Here is an example, again drawn from the implementation of the Groups package:

virtual const char* SBMLExtension::(int typeCode) const;

For example, the method for the Groups extension is implemented as shown below:

static const char* SBML_GROUPS_TYPECODE_STRINGS[] =
{
"Group"
, "Member"
};
const char* GroupsExtension::getStringFromTypeCode(int typeCode) const
{
int min = SBML_GROUPS_GROUP;
int max = SBML_GROUPS_MEMBER;
if (typeCode < min || typeCode > max)
{
return "(Unknown SBML Groups Type)";
}
return SBML_GROUPS_TYPECODE_STRINGS[typeCode - min];
}

9. Implement an init() method

Implement a static void init() method in the derived class. This method serves to encapsulate initialization code that creates an instance of the derived class and registration code that registers the instance with the SBMLExtensionRegistry class.

For example, the init() method for the Groups package is implemented as follows:

void GroupsExtension::init()
{
// 1. Check if the Groups package has already been registered.
if ( SBMLExtensionRegistry::getInstance().isRegistered(getPackageName()) )
{
// do nothing;
return;
}
// 2. Create an SBMLExtension derived object.
GroupsExtension gext;
// 3. Create SBasePluginCreator-derived objects. The derived classes
// can be instantiated by using the following template class:
//
// template<class SBasePluginType> class SBasePluginCreator
//
// The constructor of the creator class takes two arguments:
//
// 1) SBaseExtensionPoint: extension point to which the plugin connects
// 2) std::vector<std::string>: a vector that contains a list of URI
// (package versions) supported by the plugin object.
//
// For example, two plugin objects are required as part of the Groups
// implementation: one plugged into SBMLDocument and one into Model.
// For the former, since the specification for the SBML Groups package
// mandates that the 'required' flag is always 'false', the existing
// SBMLDocumentPluginNotRequired class can be used as-is as part of
// the implementation. For Model, since the lists of supported
// package versions (currently only SBML L3V1 Groups V1) are equal
// in the both plugin objects, the same vector can be handed to each
// constructor.
std::vector<std::string> pkgURIs;
pkgURIs.push_back(getXmlnsL3V1V1());
SBaseExtensionPoint docExtPoint("core", SBML_DOCUMENT);
SBaseExtensionPoint modelExtPoint("core", SBML_MODEL);
SBasePluginCreator<GroupsSBMLDocumentPlugin, GroupsExtension> docPluginCreator(docExtPoint, pkgURIs);
SBasePluginCreator<GroupsModelPlugin, GroupsExtension> modelPluginCreator(modelExtPoint, pkgURIs);
// 4. Add the above objects to the SBMLExtension-derived object.
gext.addSBasePluginCreator(&docPluginCreator);
gext.addSBasePluginCreator(&modelPluginCreator);
// 5. Register the SBMLExtension-derived object with the extension
// registry, SBMLExtensionRegistry.
int result = SBMLExtensionRegistry::getInstance().addExtension(&gext);
if (result != LIBSBML_OPERATION_SUCCESS)
{
std::cerr << "[Error] GroupsExtension::init() failed." << std::endl;
}
}

10. Instantiate a SBMLExtensionRegister object

Instantiate a global SBMLExtensionRegister object using the class derived from SBMLExtension (discussed above). Here is an example for the Groups package extension, for the object GroupsExtension. This could is placed in the GroupsExtension.cpp:

static SBMLExtensionRegister<GroupsExtension> groupsExtensionRegister;

The init() method on GroupsExtension is automatically invoked when the "register" object is instantiated. This results in initialization and registration of the package extension with libSBML.