Data structure and method for dynamic type resolution using object-oriented programming language representation of information object sets6052526Abstract A data structure and method for dynamic type resolution in mapping abstract syntax notation (ASN.1) onto an object-oriented programming language (C++). For each information object class in ASN.1, two C++ classes are generating, a "set class" that models information object sets in that ASN.1 class, and a "class class" that models information objects in that ASN.1 class. For each information object set in an ASN.1 module class, a C++ data member is defined and a virtual resolve method is generated that may be invoked during the decoding process to permit dynamic extension of each information object set. A coder environment is provided in C++ that has pointers to instances of the various C++ module classes, enabling selective control of the type resolution information presented to the decoder. Claims What is claimed is: Description FIELD OF THE INVENTION
______________________________________
class ASN1::WorkingSet
public:
virtual .about.WorkingSet();
virtual WorkingSet* clone() = 0;
virtual const WorkingSet* clone() const = 0;
protected:
WorkingSet();
WorkingSet( const WorkingSet& );
WorkingSet& operator= ( const WorkingSet& );
};
______________________________________
The generated C++ class inherits from the abstract base class "ASN1::WorkingSet". The abstract base class is empty, existing only to provide a common base to keep all heterogeneous working set classes and specific working set subclass instances in a single container. The public methods of the base class are limited to its destructor and a pure virtual "clone" method to be provide by subclasses. The protected methods include the construct and copy functions so that the class can only be instantiated using a subclass. For working set class 100, there is one or more module classes 150 that are in turn defined. For each line of ASN.1 source code scanned (110), if end of file (120) is not detected, the source code is checked (140) to detect for the syntax for the beginning of a module. If not, then the next line of source code is scanned (110). If module begin syntax is detected (140), then the beginning of a module class in C++ is generated (150). If an information object set is encountered (160) in the ASN.1 source code, then two steps are performed (170). First, a data member is created of the information object class (170(a)); second a virtual resolve function is created for the set (170(b)). Next, the ASN.1 source code syntax is checked to determine if it indicates the end of the module (180). If not, the next line of the ASN.1 input is scanned (190) and the process repeats by detecting if the input line contains an information object set (160). If module end syntax is detected (180), the process ends by defining the end of the module class (200(a)) and by generating a data member whose type is a pointer to an instance of the particular module class that was just generated (200(b)). A pro forma abstract base class for modules in C++ is provided below:
______________________________________
class ASN1::Module
public:
virtual .about.Module();
virtual Module* clone() = 0;
virtual const Module* clone() const = 0;
protected:
Module();
Module( const Module& );
Module& operator= ( const Module& );
};
______________________________________
This module class is similar to the pro forma abstract base class for working sets as described above, and has the same features and attributes. In particular, it is an abstract base class enabling specific module subclass instances to be stored in a common container. Again, for convenience, the same module name is used in the C++ code as in the ASN.1 source code. The following detailed example will further illustrate how working sets and modules are mapped from abstract syntax notation onto object-oriented programming language. The following abstract syntax (ASN.1) source code has one working set with two modules:
______________________________________
<WorkingSet MyWorkingSet MyModule1,MyModule2>--
MyModule1 {1 2 3 4 1} DEFINITIONS ::= BEGIN
SomeTbl SOME.sub.-- TBL ::= {...}
END
MyModule2 {1 2 3 4 2} DEFINITIONS ::= BEGIN
END
______________________________________
Note that the syntax "::=BEGIN" is used to detect the beginning of the particular module (140), and that the syntax "END" is used to detect the end of that module (180). The line "SomeTbl SOME.sub.-- TBL ::={ . . . }" is an example of an information object set. (The precise syntax of an information object set is described in X.682. The distinguishing convention is an initially capitalized token "SomeTbl", which names the set. This is followed by an entirely capitalized token "SOME.sub.-- TBL", which names the information object class that defines the structure of its elements. Finally, this is followed by the "::=". The ellipsis indicates that this information object set is dynamically extensible.) This abstract syntax is converted using the process shown in FIG. 1 into the following C++ source code:
______________________________________
class MyWorkingSet : public ASN1::WorkingSet
{
public:
// standard construct/copy/destroy
MyWorkingSet ( ) ;
MyWorkingSet ( const MyWorkingSet& ) ;
MyWorkingSet& operator= ( const MyWorkingSet& );
virtual .about.MyWorkingSet ( ) ;
virtual WorkingSet* clone ( ) ;
virtual const WorkingSet* clone ( ) const;
// one class for each module
class MyModule1 : public ASN1::Module
public:
// standard construct/copy/destroy
MyModule1( ) ;
virtual .about.MyModule1 ( ) ;
MyModule1( const MyModule1& ) ;
MyModule1& operator=( const MyModule1& ) ;
virtual Module* clone ( ) ;
virtual const Module* clone ( ) const;
// any information object sets go here
// as public data elements
SOME.sub.-- TBL SomeTbl;
virtual bool resolve.sub.-- SomeTbl(SOME.sub.-- TBL&
someTbl,
const
SOME.sub.-- TBL::key.sub.-- type& key,
ASN1::CoderEnv*
env)
{ return false; }
};
class MyModule2 : public ASN1::Module
{
public:
// standard construct/copy/destroy
MyModule2 ( ) ;
.about.MyModule2 ( ) ;
MyModule2( const MyModule2& ) ;
MyModule2& operator=( const MyModule2& );
virtual Module* clone ( ) ;
virtual const Module* clone ( ) const;
};
// constructor with modules provided
MyWorkingSet ( MyModule1*, MyModule2* );
// one public data element for each module
MyModule1* const myModule1;
MyModule2* const myModule2;
};
______________________________________
Note that lines beginning with "//" are comment lines provided solely to aid the reader in understanding the functional aspects of each section of code. The result of this mapping from ASN.1 to C++ is to generate for each module in a working set a working set class that contains a nested C++ class that represents the module and contains instances of any information objects sets defined in that module. In the above C++ code, the first class defined is "class MyWorkingSet", which encloses all classes generated in this compiler pass. This is generated by begin definition of working set class 100, as shown in FIG. 1. Much of this is standard boilerplate C++ code for defining basic attributes of a C++ class and is well known to those skilled in the art. The next class corresponds to the first module, "class MyModule1". This code is generated by begin definition of module class 150. After the preliminary methods are defined for the standard construct, copy and destroy features, the information object set "SOME.sub.-- TBL" is defined, as generated by process 170. For each information object set, a type-safe virtual callback function is defined within the nested C++ class for the module (the second step in process 170). The callback is to be invoked by the decoder when it searches an information object set and cannot find a particular key, providing the opportunity to dynamically extend the information object set and to supply the wanted key. The name of the callback function is resolve.sub.-- <ioset>" where "<ioset>" is the name of the information object set associated with the callback. The arguments to the callback include the information object set, the key which was not found, and the CoderEnv. The generated working set class contains one instance of each module class defined within it. The public interface to these instances is through const pointer public data members. This mechanism allows the working set class to be subclassed by the user, and to instantiate subclasses of the module classes. This is how a user would provide callback functionality. The next class in the above C++ code corresponds to "MyModule2" in the ASN.1 code, which does not include any information object sets. That class, "class MyModule2", thus contains the standard construct, copy and destroy features without the data member and virtual resolve for "class MyModule1" that corresponds to the information object set in that module and resulting C++ class. Finally, the last two groups of C++ code above correspond to end definition of working set class 130. It contains a constructor with the two modules provided, and one public data element for each module. FIG. 2 shows the procedure for mapping information object classes in abstract syntax notation into the object-oriented programming language. For each information object class in abstract syntax, two classes are generated in the object-oriented programming language. One class represents information objects of that information object class; the other represents information object sets of that information object class. In C++, the latter is a Standard Template Library (STL) container class whose name is the same as the information object set, while the former is "value.sub.-- type" within the scope of the container class, since it represents an element of the container. (STL is provided by ANSI/C++ programming language.) As shown in FIG. 2, ASN.1 input 30 is scanned (300) line by line until the end of file is detected (310), indicating the end of the source code. For each line of code, the source code is checked (320) to determine if the line contains the appropriate syntax designating the beginning of a module (i.e., "::=BEGIN"). If not, the process continues and another line of ASN.1 input 30 is scanned (300); if so, a namespace is opened (330) for the class using the same name used in the ASN.1 module. Next, if an information object class is detected (340) in the ASN.1 source code, the following tasks are performed. First, a set class definition is begun (350) in C++. Second, a class class is defined in C++ as a value.sub.-- type (360), which is more fully described in FIG. 3. Third, a standard STL set interface is created (370). Fourth, the set class definition is ended (380), closing the C++ class. After these tasks are performed, or if no information object class is detected (340), the ASN.1 module is checked (390) to the module has ended. If so, the namespace module is closed (410) and the final "};" is inserted in the C++ code; otherwise, the next line of ASN.1 input is scanned (400) to determine if an information object class is detected (340), and the proces is continued for each information object class in the module. The third task of defining the class class for an information object set is described in greater detail in FIG. 3. An information object class in ASN.1 is defined in C++ as a class value.sub.-- type (500). Next, the next line of the abstract syntax source code is scanned (510) to search for fields in each line of code--each field representing a separate component in the structure of the information object class. For each field detected (520), a separate class in C++ is created (530) with appropriate type definitions, and accessor methods are created (530) for each field. These steps define class class (360) in FIG. 2. An example of the process of mapping abstract syntax of information object classes more particularly illustrates the steps shown in the flow charts of FIGS. 2-3. The C++ classes generated from abstract base classes inherit from two pro forma base classes, one for information objects and another for information object sets. The pro forma base classes are as shown below:
______________________________________
//
// Pro forma abstract base class for information objects
//
namespace ASN1 {
class InfoObject
public:
virtual .about.InfoObject ( ) ;
virtual InfoObject* clone ( ) = 0;
virtual const InfoObject* clone ( ) const = 0;
friend bool operator== ( const InfoObject&, const InfoObject&
};
friend bool operator< ( const InfoObject&, const InfoObject& );
protected:
InfoObject ( ) ;
InfoObject( const InfoObject& );
InfoObject& operator= ( constInfoObject& );
};
};
//
// Pro forma abstract base class for information object sets
//
namespace ASN1 {
class InfoObjectSet
{
public:
virtual .about.InfoObjectSet ( ) ;
virtual InfoObjectSet* clone ( ) = 0;
virtual const InfoObjectSet* clone ( ) const = 0;
friend bool operator== ( const InfoObjectSet&, const
InfoObjectSet& );
friend bool operator< ( const InfoObjectSet&, const
InfoObjectSet& );
protected;
InfoObjectSet ( ) ;
InfoObjectSet( const InfoObjectSet& );
InfoObjectSet& operator= ( const InfoObjectSet& );
};
};
______________________________________
These two classes are abstract to allow specific information object subclass instances and specific information object set subclass instances, respectively, to be stored in a common container. The only public methods of the base classes are their destructor and a pure virtual "clone" method to be provided by subclasses. The protected methods include the construct and copy enabling the class to be abstract and to permit only subclasses to be instantiated. The abstract syntax in ASN.1 for a particular module containing an information object class called MY-CLASS having two fields, "id" and "Type", is shown below:
______________________________________
MyModule1 {1 2 3 4 1} DEFINITIONS ::= BEGIN
MY-CLASS ::= CLASS {
&id INTEGER UNIQUE,
&Type
END
______________________________________
The precise syntax of information object classes is specified in X.682, but roughly speaking, the "::=" token and "CLASS" keyword introduce the definition of an information object class named by the preceding token (e.g., "MY.sub.-- CLASS"), with the definition that follows enclosed in braces. Each field in the information object class definition is indicated by an initial ampersand `&` followed by the field name. A comma-separated list of fields is contained within the braces. Each of these syntaxes is respectively used by detect information object class 340 in FIG. 2 and field detector 520 in FIG. 3. The above ASN.1 syntax is converted or mapped into the following C++ code:
______________________________________
namespace MyModule {
class MY.sub.-- CLASS : public ASN1::InfoObjectSet {
typedef ASN1.sub.-- Integer key.sub.-- type;
class value.sub.-- type : public ASN1::InfoObject {
class id {
typedef ASN1::Integer value.sub.-- type;
typedef value.sub.-- type& reference;
typedef const value.sub.-- type& const.sub.-- reference;
typedef value.sub.-- type* pointer;
typedef const value.sub.-- type* const.sub.-- pointer;
};
class Type {
typedef ASN1::Type* value.sub.-- type;
typedef value.sub.-- type& reference;
typedef const value.sub.-- type& const.sub.-- reference;
typedef value.sub.-- type* pointer;
typedef const value.sub.-- type* const.sub.-- pointer;
};
id::const.sub.-- reference get.sub.-- id( ) const;
id::reference ref.sub.-- id( ) ;
id::reference set.sub.-- id( const id::value.sub.-- type& );
Type::const.sub.-- reference get.sub.-- Type( ) const;
Type::reference ref.sub.-- Type ( );
Type::reference set.sub.-- Type( const Type::value.sub.-- type&
};
};
typedef value.sub.-- type& reference;
typedef const value.sub.-- type& const.sub.-- reference;
typedef value.sub.-- type* iterator;
typedef const value.sub.-- type* const.sub.-- iterator;
typedef size.sub.-- t size.sub.-- type;
//
// standard STL map interface
//
MY.sub.-- CLASS ( ) ;
MY.sub.-- CLASS( const MY.sub.-- CLASS& that );
MY.sub.-- CLASSS& operator= ( const MY.sub.-- CLASS& that ) ;
virtual .about.MY.sub.-- CLASS( ) ;
const.sub.-- iterator begin( ) const;
const.sub.-- iterator end( ) const;
iterator begin( ) ;
iterator end( ) ;
bool empty( ) const;
size.sub.-- type size( ) const;
size.sub.-- type max.sub.-- size( ) const;
const value.sub.-- type& operator[ ] ( const key.sub.-- type& )
const;
value.sub.-- type& operator[ ] ( const key.sub.-- type& );
iterator insert( iterator, const.sub.-- reference x ) ;
void insert( const.sub.-- iterator q1, const.sub.-- iterator q2 );
iterator insert( const.sub.-- reference x ) ;
size.sub.-- type erase( const key.sub.-- type& key ) ;
void erase( iterator q ) ;
void erase( iterator first, iterator last ) ;
const.sub.-- iterator find( const key.sub.-- type& key ) const;
iterator find( const key.sub.-- type& key ) ;
size.sub.-- type count( const key.sub.-- type& key ) const;
const.sub.-- iterator lower.sub.-- bound( const key.sub.-- type& key )
const;
iterator lower.sub.-- bound( const key.sub.-- type& key );
const.sub.-- iterator upper.sub.-- bound( const key.sub.-- type& key )
const;
iterator upper.sub.-- bound( const key.sub.-- type& key ) ;
const.sub.-- iterator equal.sub.-- range( const key.sub.-- type& key );
const;
iterator equal.sub.-- range( const key.sub.-- type& key ) ;
friend bool operator== ( const MY.sub.-- CLASS&, const
MY.sub.-- CLASS& ) ;
friend bool operator< ( const MY.sub.-- CLASS&, const
MY.sub.-- CLASS& ) ;
};
};
______________________________________
As we track the conversion of the ASN.1 syntax to C++ code along with the flow charts in FIGS. 2-3, we see that module begin detector 320 detects the "::=BEGIN" in the first line of the ASN.1 code, and begin module namespace 330 generates "namespace MyModule" in the first line of the C++ code. Within the scope of the namespace, we generate a C++ class named "MY.sub.-- CLASS" to model information object sets of the information object class MY-CLASS. The interface for this "set class" will conform to the STL map interface. The first element of this class, in accordance with the STL map convention, is the key.sub.-- type. The type used for the key.sub.-- type is based on the ASN.1 type of the field marked "UNIQUE" in the definition of the information object class being modeled. This is generated by begin definition of set class 350 in FIG. 2. The next element of the set class is the value.sub.-- type, where we generate an inline nested class definition to model information objects of this information object class (the "class class"). This is generated by define class class 360, as shown in FIGS. 2-3. The class class contains scope classes and accessor methods for each field in the definition of the information object class being modeled. The name of each scope class is the name of the corresponding field in the information object class definition, and the accessor method names are related to the field name in a standard manner, preceding "get.sub.-- " "set.sub.-- ", and "ref.sub.-- " as appropriate. In the example shown here, the scope classes are named "id" and "Type", and the accessor methods are named "get.sub.-- id", "ref.sub.-- id", "set.sub.-- id", "get.sub.-- Type", and so forth. This process detailed in FIG. 3 is more fully explained in NMF-040, and will be understood by those skilled in the art. After the value.sub.-- type class generation is complete, STL map interface 370 in FIG. 2 generates the remainder of the standard STL map interface based on the key.sub.-- type and value.sub.-- type. These lines are the five immediately above the comments lines reading "standard STL map interface", and all lines that follow (with the exception of the final close module namespace bracket "};" generated by close module namespace 410). The process for decoding the data and type information, and in particular the dynamic type resolution information, within the OSI protocol requirements is shown in FIG. 4. Encoded data 600 is scanned (610) until the end of file is detected (620). Each subsequent data type component is checked to determine if is an "open" data type (630). If not, then the data component is decoded (640) in accordance with the predetermined type information, and the next data type information is scanned (610) and the process continued. If the data component is an open type, it is further checked to determine if it is constrained (650). If the open type is not constrained, or if deferred decoding has been specified, the data type is simply skipped over (660) and left in an undecoded buffer. If the open data type is constrained, the modules in the coder environment are searched (670) to find the particular constraining information object set for that constrained open data type. If no constraining information object set is available in the coder environment, an exception is thrown (690). If the open type is constrained and the information object set is found in the coder environment, then that information object set is searched (700) to determine if there is a constraining key value in the information object set. If a key value is found, the data type component is decoded (720) in accordance with the type resolution associated with that key, and the next data type component is scanned (610). If no key value is found in the information object set, the "resolve" virtual method or callback (730) is invoked. If the resolve virtual method returns a true value (740), then the information object set is searched again (750) to determine if the key value has been added by the callback (760). If the desired key is now found, the data type component is decoded (720) in accordance with the key value and the associated type resolution information. If the callback returns a false value (740), or if the desired key is still not found after the callback (730), then the information object set is checked (770) to determine if it is extensible. If the set is not extensible, an exception is returned (790). If the set is extensible, then the data type component is left undecoded (780). Otherwise, an exception is thrown (790). In order for an application to conveniently manage the dynamic type resolution information contained in module class instances, a "coder environment" class "CoderEnv" is introduced that serves as a container of module pointers. The container offers the standard STL set interface, with a few convenience methods added (for example, to insert entire working sets into the container). The element of the container is a module pointer rather than a module instance, allowing the class to contain subclasses of module, allowing the module instances to be modified after being inserted into the CoderEnv, and allowing one module instance to be shared among several CoderEnv instances. The coder environment is the means by which particular instances of dynamic type resolution information are made available to the decoding function. The coder environment class may be subclassed, with instances of the subclass passed to the coding services functions. This is particularly useful if the coding services invoke user callbacks, allowing the coder environment instance to be passed to those callbacks. Adding subclasses further enables the user to add his own context information that would then be available within user callbacks from the coding services. The definition of the coding environment class in C++ is provided below:
______________________________________
class ASN1::CoderEnv {
public:
//
// STL set<ASN1::Module*> interface
//
typedef ASN1::Module* key.sub.-- type;
typedef ASN1::Module* value.sub.-- type;
typedef value.sub.-- type& reference;
typedef const value.sub.-- type& const.sub.-- reference;
typedef value.sub.-- type* pointer;
typedef const value.sub.-- type* const.sub.-- pointer;
CoderEnv( ) ;
CoderEnv( const CoderEnv& that ) ;
CoderEnv& operator= ( const CoderEnv& that ) ;
virtual .about.CoderEnv( ) ;
const.sub.-- iterator begin( ) const;
const.sub.-- iterator end( ) const;
iterator begin( );
iterator end( );
bool empty( ) const;
size.sub.-- type size( ) const;
size.sub.-- type max.sub.-- size( ) const;
iterator insert( const value.sub.-- type& val ) :
iterator insert( iterator, const value.sub.-- type& val ) ;
void insert( const.sub.-- iterator q1, const.sub.-- iterators q2 );
size.sub.-- type erase( const value.sub.-- type& val ) ;
void erase( iterator q ) ;
void erase( iterator first, iterator last ) ;
const.sub.-- iterator find( const value.sub.-- type& val ) const;
iterator find( const value.sub.-- type& val ) ;
size.sub.-- type count( const value.sub.-- type* val ) const;
const.sub.-- iterator lower.sub.-- bound( const value.sub.-- type& val )
const;
iterator lower.sub.-- bound( const value.sub.-- type& val ) ;
const.sub.-- iterator upper.sub.-- bound( const value.sub.-- type& val )
const;
iterator upper.sub.-- bound( const value.sub.-- type& val ) ;
const.sub.-- iterator equal.sub.-- range( const value.sub.-- type& val )
const;
iterator equal.sub.-- range( const value.sub.-- type& val ) ;
friend bool operator== ( const CoderEnv&, const CoderEnv& ) ;
friend bool operator< ( const CoderEnv&, const CoderEnv& ) ;
//
// also allow insertion via a WorkingSet
//
iterator insert( const ASN1::WorkingSet* val ) ;
//
// PDUInfoSet information object set as public data
//
PDUINFO.sub.-- PDUInfoSet;
};
______________________________________
Note that the value.sub.-- type of the set in the ASN1::CoderEnv class is an ASN1::Module pointer, and not an instance. Although this requires the user to manage the memory for each module instance, module instances may be easily modifiable even after it has been inserted into a CoderEnv instance. Also, it affords the API user the flexibility of sharing module instances between several CoderEnv instances if it is useful. The coder environment has other features not directly related to this invention, and is more fully explained in NMF-040. The preferred embodiment of the present invention uses an octet iterator template interface for encoding and decoding for communication with a remote entity, as described in NMF-040. While the preferred embodiment uses C++ as the object-oriented programming language, other object-oriented programming languages may alternately be used. Additional advantages and modifications will readily occur to those skilled in the art. Thus while the preferred embodiment of the present invention has been disclosed and described herein, the invention in its broader aspects is not limited to the specific details, methods and representative devices shown and described herein. It will be understood by those skilled in the art that various changes in form and detail may be made therein without departing from the spirit and scope of the general inventive concept as defined by the appended claims and their equivalents.
|
Same subclass Same class Consider this |
||||||||||
