libSBML C++ API  5.20.2
Detailed explanation of each package extension class

This section lists the classes available in libSBML as part of the facilities that enable the creation of extensions to support SBML Level 3 packages. For each class, we provide a detailed explanation of how it is meant to be used in the implementation of a package extension. These classes are found in the directory src/sbml/extension/ in the libSBML source code distribution.

The classes are listed in alphabetical order on this page, but this is not necessarily the most easily digestible order in which to read about the different classes. The introductory section, Summary of the package extension mechanism, may be a better starting point for learning more about the libSBML package extension system.

SBaseExtensionPoint

This class is used as part of the mechanism that connects plugin objects (implemented using SBasePlugin or SBMLDocumentPlugin) to a given package extension. For instance, an implementation of an extended version of Model (e.g., LayoutModelPlugin in the Layout package) would involve the creation of an extension point using SBaseExtensionPoint and a mediator object created using SBasePluginCreator, to "plug" the extended Model object (LayoutModelPlugin) into the overall LayoutExtension object.

The use of SBaseExtensionPoint is relatively straightforward. The class needs to be used for each extended SBML object implemented using SBMLDocumentPlugin or SBasePlugin. Doing so requires knowing just two things:

  • The short-form name of the parent package being extended. The parent package is often simply core SBML, identified in libSBML by the nickname "core", but a SBML Level 3 package could conceivably extend another Level 3 package.
  • The libSBML type code assigned to the object being extended. For example, if an extension of Model is implemented, the relevant type code is SBMLTypeCode_t::SBML_MODEL, found in SBMLTypeCode_t.

The typical use of SBaseExtensionPoint is illustrated by the following code fragment:

SBaseExtensionPoint docExtPoint("core", SBML_DOCUMENT);
SBaseExtensionPoint modelExtPoint("core", SBML_MODEL);
SBasePluginCreator<GroupsModelPlugin, GroupsExtension> modelPluginCreator(modelExtPoint, pkgURIs);
@ SBML_MODEL
Definition: SBMLTypeCodes.h:75
@ SBML_DOCUMENT
Definition: SBMLTypeCodes.h:68
Definition: SBaseExtensionPoint.h:65
Definition: SBasePluginCreator.h:64

The code above shows two core SBML components being extended: the document object, and the Model object. These extended objects are created elsewhere (not shown) as the GroupsSBMLDocumentPlugin and GroupsModelPlugin objects. The corresponding SBaseExtensionPoint objects are handed as arguments to the constructor for SBasePluginCreator to create the connection between the extended core components and the overall package extension (here, for the Groups package, with the GroupsExtension object).

The code above is typically placed in the implementation of the init() method of the package class derived from SBMLExtension. (For the example above, it would be in the GroupsExtension.cpp file.)

SBasePlugin

LibSBML package extensions can extend existing libSBML objects such as Model using SBasePlugin as a base class, to hold attributes and/or subcomponents necessary for the SBML package being implemented. Package developers must implement an SBasePlugin extended class for each element to be extended (e.g., Model, Reaction, and others) where additional attributes and/or top-level objects of the package extension are directly contained. The following subsections detail the basic steps necessary to use SBasePlugin for the implementation of a class extension.

1. Identify the SBML components that need to be extended

The specification for a SBML Level 3 package will define the attributes and subojects that make up the package constructs. Those constructs that modify existing SBML components such as Model, Reaction, etc., will be the ones that need to be extended using SBasePlugin.

For example, the Layout package makes additions to Model, SpeciesReference, and the <sbml> element (which is represented in libSBML by SBMLDocument). This means that the Layout package extension in libSBML needs to define extended versions of Model, SpeciesReference and SBMLDocument. Elements other than the SBML document need to be implemented using SBasePlugin; the document component must be implemented using SBMLDocumentPlugin instead.

2. Create a SBasePlugin subclass for each extended SBML component

A new class definition that subclasses SBasePlugin needs to be created for each SBML component to be extended by the package. For instance, the Layout package needs LayoutModelPlugin and LayoutSpeciesReferencePlugin. (As mentioned above, the Layout class also needs LayoutSBMLDocumentPlugin, but this one is implemented using SBMLDocumentPlugin instead of SBasePlugin.) Below, we describe in detail the different parts of an SBasePlugin subclass definition.

2.1 Define protected data members

Data attributes on each extended class in an SBML package will have one of the data types std::string, double, int, or bool. Subelements/subobjects will normally be derived from the ListOf class or from SBase.

The additional data members must be properly initialized in the class constructor, and must be properly copied in the copy constructor and assignment operator. For example, the following data member is defined in the GroupsModelPlugin class (in the file GroupsModelPlugin.h):

ListOfGroups mGroups;
Definition: ListOfGroups.h:85

2.2 Override SBasePlugin class-related methods

The derived class must override the constructor, copy constructor, assignment operator (operator=) and clone() methods from SBasePlugin.

2.3 Override SBasePlugin virtual methods for attributes

If the extended component is defined by the SBML Level 3 package to have attributes, then the extended class definition needs to override the following internal methods on SBasePlugin and provide appropriate implementations:

  • addExpectedAttributes(ExpectedAttributes& attributes): This method should add the attributes that are expected to be found on this kind of extended component in an SBML file or data stream.
  • readAttributes(XMLAttributes& attributes, ExpectedAttributes& expectedAttributes): This method should read the attributes expected to be found on this kind of extended component in an SBML file or data stream.
  • hasRequiredAttributes(): This method should return true if all of the required attribute for this extended component are present on instance of the object.
  • writeAttributes(XMLOutputStream& stream): This method should write out the attributes of an extended component. The implementation should use the different kinds of writeAttribute methods defined by XMLOutputStream to achieve this.

2.4 Override SBasePlugin virtual methods for subcomponents

If the extended component is defined by the Level 3 package to have subcomponents (i.e., full XML elements rather than mere attributes), then the extended class definition needs to override the following internal SBasePlugin methods and provide appropriate implementations:

  • createObject(XMLInputStream& stream): Subclasses must override this method to create, store, and then return an SBML object corresponding to the next XMLToken in the XMLInputStream. To do this, implementations can use methods like peek() on XMLInputStream to test if the next object in the stream is something expected for the package. For example, LayoutModelPlugin uses peek() to examine the next element in the input stream, then tests that element against the Layout namespace and the element name "listOfLayouts" to see if it's the single subcomponent (ListOfLayouts) permitted on a Model object using the Layout package. If it is, it returns the appropriate object.
  • connectToParent(SBase *sbase): This creates a parent-child relationship between a given extended component and its subcomponent(s).
  • setSBMLDocument(SBMLDocument* d): This method should set the parent SBMLDocument object on the subcomponent object instances, so that the subcomponent instances know which SBMLDocument contains them.
  • enablePackageInternal(std::string& pkgURI, std::string& pkgPrefix, bool flag): This method should enable or disable the subcomponent based on whether a given XML namespace is active.
  • writeElements(XMLOutputStream& stream): This method must be overridden to provide an implementation that will write out the expected subcomponents/subelements to the XML output stream.
  • readOtherXML(SBase* parentObject, XMLInputStream& stream): This function should be overridden if elements of annotation, notes, MathML content, etc., need to be directly parsed from the given XMLInputStream object.
  • hasRequiredElements(): This method should return true if a given object contains all the required subcomponents defined by the specification for that SBML Level 3 package.

2.5 Override SBasePlugin virtual methods for XML namespaces

If the package needs to add additional xmlns attributes to declare additional XML namespace URIs, the extended class should override the following method:

  • writeXMLNS(XMLOutputStream& stream): This method should write out any additional XML namespaces that might be needed by a package implementation.

2.6 Implement additional methods as needed

Extended component implementations can add whatever additional utility methods are useful for their implementation.

SBasePluginCreator

SBMLDocumentPlugin

The following subsections detail the basic steps necessary to use SBMLDocumentPlugin to extend SBMLDocument for a given package extension.

1. Identify the changes necessary to SBMLDocument

The specification for a SBML Level 3 package will define the changes to the SBML <sbml> element. Packages typically do not make any changes beyond adding an attribute named "required" (discussed below), so in most cases, the extension of SBMLDocument is very simple. However, some packages do more. For instance, the Hierarchical Model Composition package adds subobjects for lists of model definitions. SBMLDocumentPlugin supports all these cases.

2. Create the SBMLDocumentPlugin subclass

A package extension will only define one subclass of SBMLDocumentPlugin. Below, we describe in detail the different parts of a subclass definition.

2.1 Override SBasePlugin class-related methods

The derived class must override the constructor, copy constructor, assignment operator (operator=) and clone() methods from SBasePlugin.

2.2 Determine the necessary value of the "required" attribute

At minimum, it is necessary for a package implementation to add the "required" attribute to the SBML <sbml> element mandated by SBML for all Level 3 packages, and this is done using this class as a base. If the 'required' attribute is the only addition necessary for a particular SBML Level 3 package, then the subclass of SBMLDocumentPlugin for the package can have a very simple implementation. Some Level 3 packages add additional attributes or elements to <sbml>, and their implementations would go into the subclassed SBMLDocumentPlugin.

SBMLDocumentPlugin provides methods with default implementations that support managing the "required" attribute, so package extension code does not need to provide implementations—they only need to set the correct value for the SBML Level 3 package based on its specification. The following are the virtual methods for working with the "required" attribute. Package extensions would only need to override them in special circumstances:

  • setRequired(bool value): This method sets the value of the flag.
  • getRequired(): This method gets the value of the "required" flag.
  • isSetRequired(): This method tests if the value has been set.
  • unsetRequired(): This method unsets the value of the "required" flag.

2.3 Define protected data members

An extended SBMLDocument object may need more than just the "required" attribute, depending on what is defined in the specification for the package being implemented. Data attributes on the extended <sbml> object in an SBML package will have one of the data types std::string, double, int, or bool. Subelements/subobjects will normally be derived from the ListOf class or from SBase.

The additional data members must be properly initialized in the class constructor, and must be properly copied in the copy constructor and assignment operator.

2.4 Override virtual methods for attributes

If the extended component is defined by the SBML Level 3 package to have attributes, then the extended SBMLDocumentPlugin class definition needs to override the following internal methods that come from SBasePlugin (the base class of SBMLDocumentPlugin) and provide appropriate implementations:

  • addExpectedAttributes(ExpectedAttributes& attributes): This method should add the attributes that are expected to be found on this kind of extended component in an SBML file or data stream.
  • readAttributes(XMLAttributes& attributes, ExpectedAttributes& expectedAttributes): This method should read the attributes expected to be found on this kind of extended component in an SBML file or data stream.
  • hasRequiredAttributes(): This method should return true if all of the required attribute for this extended component are present on instance of the object.
  • writeAttributes(XMLOutputStream& stream): This method should write out the attributes of an extended component. The implementation should use the different kinds of writeAttribute methods defined by XMLOutputStream to achieve this.

2.5 Override virtual methods for subcomponents

If the extended component is defined by the Level 3 package to have subcomponents (i.e., full XML elements rather than mere attributes), then the extended class definition needs to override the following internal methods on SBasePlugin (the base class of SBMLDocumentPlugin) and provide appropriate implementations:

  • createObject(XMLInputStream& stream): Subclasses must override this method to create, store, and then return an SBML object corresponding to the next XMLToken in the XMLInputStream. To do this, implementations can use methods like peek() on XMLInputStream to test if the next object in the stream is something expected for the package. For example, LayoutModelPlugin uses peek() to examine the next element in the input stream, then tests that element against the Layout namespace and the element name "listOfLayouts" to see if it's the single subcomponent (ListOfLayouts) permitted on a Model object using the Layout package. If it is, it returns the appropriate object.
  • connectToParent(SBase *sbase): This creates a parent-child relationship between a given extended component and its subcomponent(s).
  • setSBMLDocument(SBMLDocument* d): This method should set the parent SBMLDocument object on the subcomponent object instances, so that the subcomponent instances know which SBMLDocument contains them.
  • enablePackageInternal(std::string& pkgURI, std::string& pkgPrefix, bool flag): This method should enable or disable the subcomponent based on whether a given XML namespace is active.
  • writeElements(XMLOutputStream& stream): This method must be overridden to provide an implementation that will write out the expected subcomponents/subelements to the XML output stream.
  • readOtherXML(SBase* parentObject, XMLInputStream& stream): This function should be overridden if elements of annotation, notes, MathML content, etc., need to be directly parsed from the given XMLInputStream object.
  • hasRequiredElements(): This method should return true if a given object contains all the required subcomponents defined by the specification for that SBML Level 3 package.

2.6 Override virtual methods for XML namespaces

If the package needs to add additional xmlns attributes to declare additional XML namespace URIs, the extended class should override the following method coming from SBasePlugin (the parent class of SBMLDocumentPlugin):

  • writeXMLNS(XMLOutputStream& stream): This method should write out any additional XML namespaces that might be needed by a package implementation.

2.7 Implement additional methods as needed

Extended SBMLDocumentPlugin implementations can add whatever additional utility methods are useful for their implementation.

SBMLExtension

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;
}
static const std::string & getPackageName()
Returns the nickname of the SBML Level&#160;3 package implemented by this libSBML extension.
Definition: GroupsExtension.cpp:70

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:

{
return 3;
}
{
return 1;
}
{
return 1;
}
static unsigned int getDefaultLevel()
Returns the default SBML Level implemented by this libSBML extension.
Definition: GroupsExtension.cpp:81
static unsigned int getDefaultVersion()
Returns the default SBML Version implemented by this libSBML extension.
Definition: GroupsExtension.cpp:91
static unsigned int getDefaultPackageVersion()
Returns the default version of the SBML Level&#160;3 package implemented by this libSBML extension.
Definition: GroupsExtension.cpp:102

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;
}
static const std::string & getXmlnsL3V1V1()
Returns the XML namespace URI of the SBML Level&#160;3 package implemented by this libSBML extension.
Definition: GroupsExtension.cpp:113

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;
}
{
return new GroupsExtension(*this);
}
Definition: GroupsExtension.h:85
virtual const std::string & getURI(unsigned int sbmlLevel, unsigned int sbmlVersion, unsigned int pkgVersion) const
Returns a string representing the SBML XML namespace of this SBML Level&#160;3 package.
Definition: GroupsExtension.cpp:208
virtual unsigned int getVersion(const std::string &uri) const
Returns the Version within the SBML Level for the given URI of this package.
Definition: GroupsExtension.cpp:247
virtual unsigned int getLevel(const std::string &uri) const
Returns the SBML Level for the given URI of this package.
Definition: GroupsExtension.cpp:232
virtual const std::string & getName() const
Returns the name of this SBML Level&#160;3 package ("groups").
Definition: GroupsExtension.cpp:197
virtual unsigned int getPackageVersion(const std::string &uri) const
Returns the SBML Level&#160;3 package version for the given URI of this package.
Definition: GroupsExtension.cpp:263
GroupsExtension()
Creates a new GroupsExtension instance.
Definition: GroupsExtension.cpp:146
virtual GroupsExtension * clone() const
Creates and returns a deep copy of this GroupsExtension object.
Definition: GroupsExtension.cpp:179

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.
    SBMLExtensionNamespaces< GroupsExtension > GroupsPkgNamespaces
    Required typedef definitions.
    Definition: GroupsExtension.h:355
    Definition: SBMLExtensionNamespaces.h:83

  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:

    #define LIBSBML_EXTERN
    LIBSBML_EXTERN is used under Windows to simplify exporting functions from a DLL.
    Definition: extern.h:102

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.
Definition: Group.h:177

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);
doc = new SBMLDocument(&gnps);
Definition: SBMLDocument.h:349

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:

GroupsExtension::getSBMLExtensionNamespaces(const std::string& uri) const
{
GroupsPkgNamespaces* pkgns = NULL;
if ( uri == getXmlnsL3V1V1())
{
pkgns = new GroupsPkgNamespaces(3, 1, 1);
}
return pkgns;
}
virtual SBMLNamespaces * getSBMLExtensionNamespaces(const std::string &uri) const
Returns a GroupsPkgNamespaces object.
Definition: GroupsExtension.cpp:278
Definition: SBMLNamespaces.h:145

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
{
SBMLGroupsTypeCode_t
SBMLGroupsTypeCode_t Enumeration of possible types in the libSBML “groups” package implementation.
Definition: GroupsExtension.h:381
@ SBML_GROUPS_GROUP
Definition: GroupsExtension.h:383
@ SBML_GROUPS_MEMBER
Definition: GroupsExtension.h:382

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
{
SBMLLayoutTypeCode_t
SBMLFbcTypeCode_t Enumeration of possible types in the libSBML “layout” package implementation.
Definition: LayoutExtension.h:436
@ SBML_LAYOUT_POINT
Definition: LayoutExtension.h:445
@ SBML_LAYOUT_LINESEGMENT
Definition: LayoutExtension.h:444
@ SBML_LAYOUT_SPECIESREFERENCEGLYPH
Definition: LayoutExtension.h:448
@ SBML_LAYOUT_TEXTGLYPH
Definition: LayoutExtension.h:449
@ SBML_LAYOUT_REACTIONGLYPH
Definition: LayoutExtension.h:446
@ SBML_LAYOUT_GRAPHICALOBJECT
Definition: LayoutExtension.h:442
@ SBML_LAYOUT_CUBICBEZIER
Definition: LayoutExtension.h:439
@ SBML_LAYOUT_LAYOUT
Definition: LayoutExtension.h:443
@ SBML_LAYOUT_DIMENSIONS
Definition: LayoutExtension.h:441
@ SBML_LAYOUT_BOUNDINGBOX
Definition: LayoutExtension.h:437
@ SBML_LAYOUT_CURVE
Definition: LayoutExtension.h:440
@ SBML_LAYOUT_COMPARTMENTGLYPH
Definition: LayoutExtension.h:438
@ SBML_LAYOUT_SPECIESGLYPH
Definition: LayoutExtension.h:447

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;
....
}
}
else if (pkgName == "layout") {
switch (sb->getTypeCode()) {
....
break;
....
}
}
else if (pkgName == "groups") {
switch (sb->getTypeCode()) {
....
break;
....
}
}
...
}
@ SBML_REACTION
Definition: SBMLTypeCodes.h:77
Definition: SBase.h:191
const std::string & getPackageName() const
Returns the name of the SBML Level&#160;3 package in which this element is defined.
Definition: SBase.cpp:3476
virtual int getTypeCode() const
Returns the libSBML type code for this object.
Definition: SBase.cpp:3500

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;
Definition: SBMLExtension.h:208

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];
}
static const char * SBML_GROUPS_TYPECODE_STRINGS[]
Definition: GroupsExtension.cpp:129
virtual const char * getStringFromTypeCode(int typeCode) const
Takes a type code of the “groups” package and returns a string describing the code.
Definition: GroupsExtension.cpp:296

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.
{
// do nothing;
return;
}
// 2. Create an SBMLExtension derived object.
// 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.
{
std::cerr << "[Error] GroupsExtension::init() failed." << std::endl;
}
}
int addExtension(const SBMLExtension *ext)
Add the given SBMLExtension object to this SBMLExtensionRegistry.
static SBMLExtensionRegistry & getInstance()
Returns a singleton instance of the registry.
@ LIBSBML_OPERATION_SUCCESS
Definition: operationReturnValues.h:61

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;
Definition: SBMLExtensionRegister.h:74

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.

SBMLExtensionException

Certain situations can result in an exception being thrown by libSBML package extensions. A prominent example involves the constructor for SBMLNamespaces (and its subclasses), which will throw SBMLExtensionException if the arguments it is given refer to an unknown SBML Level 3 package. The situation can arise for legitimate SBML files if the necessary package extension has not been registered with a given copy of libSBML.

SBMLExtensionNamespaces

Each package extension in libSBML needs to extend and instantiate the template class SBMLExtensionNamespaces, as well as declare a specific typedef. The following sections explain these steps in detail.

1. Define the typedef

Each package needs to declare a package-specific version of the SBMLExtensionNamespaces class using a typedef. The following example code demonstrates how this is done in the case of the Layout package:

SBMLExtensionNamespaces< LayoutExtension > LayoutPkgNamespaces
Definition: LayoutExtension.h:422

This creates a new type called LayoutPkgNamespaces. The code above is usually placed in the same file that contains the SBMLExtension-derived definition of the package extension base class. In the case of the Layout package, this is in the file src/packages/layout/extension/LayoutExtension.h in the libSBML source distribution.

2. Instantiate a template instance

Each package needs to instantiate a template instance of the SBMLExtensionNamespaces class. The following example code demonstrates how this is done in the case of the Layout package:

In the case of the Layout package, the code above is located in the file src/packages/layout/extension/LayoutExtension.cpp in the libSBML source distribution.

3. Create constructors that accept the class

Each SBase-derived class in the package extension should implement a constructor that accepts the SBMLExtensionNamespaces-derived class as an argument. For example, in the Layout package, the class BoundBox has a constructor declared as follows

Definition: BoundingBox.h:64

The implementation of this constructor must, among other things, take the argument namespace object and use it to set the XML namespace URI for the object. Again, for the BoundingBox example:

: SBase(layoutns)
,mPosition(layoutns)
,mDimensions(layoutns)
,mPositionExplicitlySet (false)
,mDimensionsExplicitlySet (false)
{
// Standard extension actions.
setElementNamespace(layoutns->getURI());
connectToChild();
// Package-specific actions.
mPosition.setElementName("position");
// Load package extensions bound with this object (if any).
loadPlugins(layoutns);
}
BoundingBox(unsigned int level=LayoutExtension::getDefaultLevel(), unsigned int version=LayoutExtension::getDefaultVersion(), unsigned int pkgVersion=LayoutExtension::getDefaultPackageVersion())
Default Constructor.
Definition: BoundingBox.cpp:76

SBMLExtensionRegister

When a package extension is first loaded, it must register itself with the registry of extensions maintained by the cleverly-named SBMLExtensionRegistry class. That registry is how other classes in libSBML access information about the packages recognized by a particular copy of libSML; a corollary is that libSBML can't parse or even recognize SBML Level 3 packages that have no corresponding extension registered with SBMLExtensionRegistry.

The SBMLExtensionRegister class is a template class for automatically registering each package extension to the SBMLExtensionRegistry class at startup time. The class and its use are very simple. An implementation of a package extension merely needs to use it to instantiate one object. The class used in the template invocation should be the extension derived from SBMLExtension (e.g., LayoutExtension for the Layout package). The following is an example:

static SBMLExtensionRegister< LayoutExtension > layoutExtensionRegistry
Definition: LayoutExtension.cpp:126

The line above is typically be placed in the .cpp file associated with the definition of the SBMLExtension-derived class; in the case of the Layout package, this is LayoutExtension.cpp.

The result of doing the above is that the init() method on LayoutExtension will be automatically invoked when the "register" object is instantiated. This results in initialization and registration of the package extension with libSBML.

SBMLExtensionRegistry

The package extension registry is implemented as a singleton instance of SBMLExtensionRegistry. The class provides only utility functionality; implementations of SBML packages do not need to implement any subclasses or methods of this class. SBMLExtensionRegistry is useful for its facilities to query the known packages, and to enable or disable packages selectively.