libSBML C API
5.18.0
|
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.
The use of SBaseExtensionPoint_t is relatively straightforward. The class needs to be used for each extended SBML object implemented using SBMLDocumentPlugin_t or SBasePlugin_t. Doing so requires knowing just two things:
"core"
, but a SBML Level 3 package could conceivably extend another Level 3 package.The typical use of SBaseExtensionPoint_t is illustrated by the following code fragment:
The code above shows two core SBML components being extended: the document object, and the Model_t object. These extended objects are created elsewhere (not shown) as the GroupsSBMLDocumentPlugin_t
and GroupsModelPlugin_t
objects. The corresponding SBaseExtensionPoint_t objects are handed as arguments to the constructor for SBasePluginCreator_t to create the connection between the extended core components and the overall package extension (here, for the Groups package, with the GroupsExtension_t
object).
The code above is typically placed in the implementation of the init()
method of the package class derived from SBMLExtension_t. (For the example above, it would be in the GroupsExtension.cpp
file.)
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_t, Reaction_t, etc., will be the ones that need to be extended using SBasePlugin_t.
For example, the Layout_t package makes additions to Model_t, SpeciesReference_t, and the <sbml>
element (which is represented in libSBML by SBMLDocument_t). This means that the Layout_t package extension in libSBML needs to define extended versions of Model_t, SpeciesReference_t and SBMLDocument_t. Elements other than the SBML document need to be implemented using SBasePlugin_t; the document component must be implemented using SBMLDocumentPlugin_t instead.
A new class definition that subclasses SBasePlugin_t needs to be created for each SBML component to be extended by the package. For instance, the Layout_t package needs LayoutModelPlugin_t and LayoutSpeciesReferencePlugin_t. (As mentioned above, the Layout_t class also needs LayoutSBMLDocumentPlugin_t, but this one is implemented using SBMLDocumentPlugin_t instead of SBasePlugin_t.) Below, we describe in detail the different parts of an SBasePlugin_t subclass definition.
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_t class or from SBase_t.
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_t
class (in the file GroupsModelPlugin.h
):
The derived class must override the constructor, copy constructor, assignment operator (operator=
) and clone()
methods from SBasePlugin_t.
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_t 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_t& 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_t& 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_t to achieve this.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_t methods and provide appropriate implementations:
createObject(XMLInputStream_t& stream)
: Subclasses must override this method to create, store, and then return an SBML object corresponding to the next XMLToken_t in the XMLInputStream_t. To do this, implementations can use methods like peek()
on XMLInputStream_t to test if the next object in the stream is something expected for the package. For example, LayoutModelPlugin_t uses peek()
to examine the next element in the input stream, then tests that element against the Layout_t namespace and the element name "listOfLayouts"
to see if it's the single subcomponent (ListOfLayouts_t) permitted on a Model_t object using the Layout_t package. If it is, it returns the appropriate object.connectToParent(SBase_t *sbase)
: This creates a parent-child relationship between a given extended component and its subcomponent(s).setSBMLDocument(SBMLDocument_t* d)
: This method should set the parent SBMLDocument_t object on the subcomponent object instances, so that the subcomponent instances know which SBMLDocument_t 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_t& 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_t* parentObject, XMLInputStream_t& stream)
: This function should be overridden if elements of annotation, notes, MathML content, etc., need to be directly parsed from the given XMLInputStream_t 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.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_t& stream)
: This method should write out any additional XML namespaces that might be needed by a package implementation.Extended component implementations can add whatever additional utility methods are useful for their implementation.
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_t is very simple. However, some packages do more. For instance, the Hierarchical Model Composition package adds subobjects for lists of model definitions. SBMLDocumentPlugin_t supports all these cases.
A package extension will only define one subclass of SBMLDocumentPlugin_t. Below, we describe in detail the different parts of a subclass definition.
The derived class must override the constructor, copy constructor, assignment operator (operator=
) and clone()
methods from SBasePlugin_t.
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_t 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_t.
SBMLDocumentPlugin_t 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.An extended SBMLDocument_t 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_t class or from SBase_t.
The additional data members must be properly initialized in the class constructor, and must be properly copied in the copy constructor and assignment operator.
If the extended component is defined by the SBML Level 3 package to have attributes, then the extended SBMLDocumentPlugin_t class definition needs to override the following internal methods that come from SBasePlugin_t (the base class of SBMLDocumentPlugin_t) 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_t& 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_t& 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_t to achieve this.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_t (the base class of SBMLDocumentPlugin_t) and provide appropriate implementations:
createObject(XMLInputStream_t& stream)
: Subclasses must override this method to create, store, and then return an SBML object corresponding to the next XMLToken_t in the XMLInputStream_t. To do this, implementations can use methods like peek()
on XMLInputStream_t to test if the next object in the stream is something expected for the package. For example, LayoutModelPlugin_t uses peek()
to examine the next element in the input stream, then tests that element against the Layout_t namespace and the element name "listOfLayouts"
to see if it's the single subcomponent (ListOfLayouts_t) permitted on a Model_t object using the Layout_t package. If it is, it returns the appropriate object.connectToParent(SBase_t *sbase)
: This creates a parent-child relationship between a given extended component and its subcomponent(s).setSBMLDocument(SBMLDocument_t* d)
: This method should set the parent SBMLDocument_t object on the subcomponent object instances, so that the subcomponent instances know which SBMLDocument_t 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_t& 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_t* parentObject, XMLInputStream_t& stream)
: This function should be overridden if elements of annotation, notes, MathML content, etc., need to be directly parsed from the given XMLInputStream_t 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.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_t (the parent class of SBMLDocumentPlugin_t):
writeXMLNS(XMLOutputStream_t& stream)
: This method should write out any additional XML namespaces that might be needed by a package implementation.Extended SBMLDocumentPlugin_t implementations can add whatever additional utility methods are useful for their implementation.
GroupsExtension_t
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.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:
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:
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()
.
Define other similar methods to return additional namespace URIs if the package extension implements other package versions or supports other SBML Level/Version combinations.
Override the following pure virtual methods on SBMLExtension_t:
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 versionvirtual SBMLExtension_t* 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:
Constructor, copy constructor, and destructor methods also must be overridden if additional data members are defined in the derived class.
Define typedef and template instantiation code for a package-specific subclass of the SBMLExtensionNamespaces_t template class. The SBMLExtensionNamespaces_t template class is a derived class of SBMLNamespaces_t and can be used as an argument of constructors of SBase_t-derived classes defined in the package extensions.
Define a typedef. For example, the typedef for GroupsExtension_t
is implemented in the file GroupsExtension.h
as follows:
Define a template instantiation for the typedef. For example, the template instantiation code for GroupsExtension_t is
implemented in the file GroupsExtension.cpp
as follows:
Here is example of how the resulting class is used. The definitions above allow a GroupsPkgNamespaces_t
object to be used when creating a new Group_t
object. The GroupsPkgNamespaces_t
is handed to the constructor as an argument, as shown below:
The GroupsPkgNamespaces_t
object can also be used when creating an SBMLDocument_t object with the Groups package. The code fragment below shows an example of this:
Override the pure virtual method getSBMLExtensionNamespaces()
, which returns an SBMLNamespaces_t derived object. For example, the method is overridden in the class GroupsExtension_t
as follows:
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:
In the enumeration above, SBML_GROUPS_GROUP
corresponds to the Group_t
class (for the <group>
element defined by the SBML Level 3 Groups package) and SBML_GROUPS_MEMBER
corresponds to the Member_t
class (for the <member>
element defined by the Level 3 Groups package), respectively.
Similarly, SBMLLayoutTypeCode_t for the Layout_t package is defined in the file LayoutExtension.h
as follows:
These enum values are returned by corresponding getTypeCode()
methods. (E.g., SBML_GROUPS_GROUP
is returned in Group_t::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:
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.
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:
For example, the method for the Groups extension is implemented as shown below:
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_t class.
For example, the init()
method for the Groups package is implemented as follows:
Instantiate a global SBMLExtensionRegister_t object using the class derived from SBMLExtension_t (discussed above). Here is an example for the Groups package extension, for the object GroupsExtension_t
. This could is placed in the GroupsExtension.cpp
:
The init()
method on GroupsExtension_t
is automatically invoked when the "register" object is instantiated. This results in initialization and registration of the package extension with libSBML.
typedef
. The following sections explain these steps in detail.Each package needs to declare a package-specific version of the SBMLExtensionNamespaces_t class using a typedef
. The following example code demonstrates how this is done in the case of the Layout_t package:
This creates a new type called LayoutPkgNamespaces_t. The code above is usually placed in the same file that contains the SBMLExtension_t-derived definition of the package extension base class. In the case of the Layout_t package, this is in the file src/packages/layout/extension/LayoutExtension.h
in the libSBML source distribution.
Each package needs to instantiate a template instance of the SBMLExtensionNamespaces_t class. The following example code demonstrates how this is done in the case of the Layout_t package:
In the case of the Layout_t package, the code above is located in the file src/packages/layout/extension/LayoutExtension.cpp
in the libSBML source distribution.
Each SBase_t-derived class in the package extension should implement a constructor that accepts the SBMLExtensionNamespaces_t-derived class as an argument. For example, in the Layout_t package, the class BoundBox has a constructor declared as follows
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_t example:
The SBMLExtensionRegister_t class is a template class for automatically registering each package extension to the SBMLExtensionRegistry_t 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_t (e.g., LayoutExtension_t for the Layout package). The following is an example:
The line above is typically be placed in the .cpp
file associated with the definition of the SBMLExtension_t-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_t
will be automatically invoked when the "register" object is instantiated. This results in initialization and registration of the package extension with libSBML.