![]() |
![]() |
![]() |
![]() |
![]() |
The AccessVisitor Class
TTCN Access is a large class library, with over 600 classes, and therefore we also need suitable tools for simplifying the creation of TTCN Access applications. The preferred solution is the usage of the class AccessVisitor, which definition is available in the C++ header file ITEXAccessVisitor.hh.
The AccessVisitor class is a very close relative to the design pattern `Visitor' (described by, for instance, Gamma, Helm, Johnson and Vlissides in `Design Patterns - Elements of reusable software', Addison-Wesley1994). The difference is that the TTCN Access classes contain runtime type information which eliminates the need for them to have dependencies to the Visitor class (and therefore there is no need for `Accept' methods in the visited classes).
An object of a class which is derived from the class AccessVisitor is later on referred to as a `visitor'.
AccessVisitor Class Members
Common Classes
The AccessVisitor class has two methods for visiting objects of common classes AccessSuite and AccessNode. These are declared
public:void Visit( const AccessNode );void Visit( const AccessSuite & );and calling them with, will start a chain of calls in the visitor which effectively is a pre-order traversal of the subtree of the AccessNode, or the complete syntactical tree of the AccessSuite.
TTCN/ASN.1 Derived Classes
The AccessVisitor class has one virtual member function for each TTCN and ASN.1 derived class in TTCN Access. Each of the member functions are declared
public:virtual void Visit<class>( const <class> & );Visitor member method for an Identifier (excerpt from ITEXAccessVisitor.hh):
class AccessVisitor{public:...virtual void VisitIdentifier(const Identifier&);virtual void VisitVerdict(const Verdict&);...};The base class implementation of this method calls the related Visit<child-class> function for all of the child objects to the current object.
If you need to change the behavior, for instance in order to generate some code or report from the TTCN Access Suite, just derive a new class from the AccessVisitor class and override the relevant method(s). Call the base class implementation of the method to traverse the children if needed.
Data Members
The AccessVisitor class contains no explicitly declared data members and is therefore stateless. It therefore makes program re-entrance possible, and several visitors may be active in the same tree/document at the same time if needed.
Using the AccessVisitor
The intended usage of the AccessVisitor class is by derivation. Derive one or several specialized classes for each of the purposes which you use TTCN Access. Override the relevant methods.
Use Case - Information Collection
It is simple to create a visitor class for collection of some kind of information from the test suite. The basic method for this is to have a handle or actual information in the visitor class.
An information collecting visitor class:
#include <time.h>#include <iostream.h>#include <ITEXAccessClasses.hh>#include <ITEXAccessVisitor.hh>//// A visitor which counts the number of testcases// in a test suite.class TestCounter : public AccessVisitor{public:TestCounter() : _count( 0 ) { }~TestCounter() { cout << _count << endl; }void VisitTestCase(const TestCase&) { _count++; }private:unsigned int _count;};// Small example usage, no real fault control...int main( int argc, char ** argv ){AccessSuite suite;if ( suite.open( argv[1] ) ) {TestCounter testCounter;testCounter.Visit( suite );}return 0;}Use Case - Code Generation
It is likewise simple to create a class for simple code generation. The following example is a class for generation of a c-style declaration which contains a list of all SimpleType names in a test suite.
An information collecting visitor class:
#include <stdio.h>#include <time.h>#include <ITEXAccessClasses.hh>#include <ITEXAccessVisitor.hh>// A visitor which generate a c-style declaration// of a null-terminated array of all Simple Type// Declarations (identifiers) in a test suite.class ListGenerator : public AccessVisitor{public:ListGenerator(FILE * f) : _file( f ) {printf( "const char *ids[]={\n");}void VisitSimpleTypeId(const SimpleTypeId& id) {printf( " \"%s\",\n", (const char*)id.simpleTypeIdentifier());}~ListGenerator() {printf( " NULL\n};\n");}};// Small example usage, no real fault control...int main( int argc, char ** argv ){AccessSuite suite;if ( suite.open( argv[1] ) ) {ListGenerator generator;generator.Visit( suite );}return 0;}The last two examples are not the most efficient implementations due to the fact that they traverse the whole tree even though we are only interested in small parts, and therefore we may want to improve the efficiency. This may be done using any of the techniques described in Optimizing Visitors.
Advanced Use Case - Combined Visitors
More advanced designs may be possible by combining several visitors for performing more advanced tasks. You may for instance have visitors which are parameterized with other visitors for specialized tasks, where you still would want to maintain decent performance and yet not have trade-offs in clarity of the design.
A TTCN Interpreter would need a mechanism for building an internal representation of values. Values are always built by using the same structure, but you may wish to have several possible representations of atomic values. A visitor could be used to generate the value objects, where one visitor is used for building the overall structure, and another is used for building individual fields. There are at least two choices available in the design:
- To inherit the structure building class into the class which builds the atomic values
- To parameterize the structure building class with the atomic value handing class (which gives you a possibility to tune the behavior at runtime).
In this example, the value building class inherits from the AccessVisitor class and the Visit<xxx> functions are used to generate a new value. The class GciValueBuilder in the example, may visit any structured type and will on the Visit<class> function either create itself a data value, or if it is a structured type, create a dynamic array, and then invoke a new visitor for each of the fields, which results will later be assigned to each of the fields in the same array. The implementation is not present in the example. It is just outlined below.
The solution of using visitors for building the values, removes the switch statements, which otherwise would undoubtedly clobber an implementation which uses Direct Access as described in a previous section.
class GciValueBuilder : public AccessVisitor{// basic structure for building/matching valuesvirtual void VisitXxxx( const Xxxx & );...// built valueGciValue * _value;};class GciValueBinaryBuilder : public GciValueBuilder{// suitable overrides for efficient binary value// handling...};class GciValueBigNumBuilder : public GciValueBuilder{// suitable ovverides for a `bignum'// implementation...};Optimizing Visitors
A visitor is a potentially inefficient way to find and process objects, since it in its unmodified version traverses the whole document, without regarding what parts of the document the inherited visitor is interested in. All optimizations are in the domain of limiting the subtree for which we are traversing. The following examples shows methods for avoiding unnecessary traversal and optimally, constant time access.
Optimizing a visitor class to avoid traversal of all parts but the declarations part, may improve performance for suite traversal by over 100 times for some fairly representable suites (since most suites contain more and larger syntactical trees in the dynamic part than in all other parts, possibly with the exception of ASN.1 constraint declarations).
class DeclarationChecker : public AccessVisitor{public:void VisitSuiteOverviewPart(const SuiteOverViewPart& ) { }void VisitConstraintsPart(const ConstraintsPart & ) { }void VisitDeclarationsPart (const DeclarationsPart & ) { }// Add the functions which actually do processing// below ...};Optimizing a visitor class to traverse only parts we are interested in, is also possible, by using one or a few levels of Direct Access instead of the default traversal.
This example skips all traversal down to the Simple Type Definitions table, and only traverses those.
class SimpleTypeIdPrinter : public AccessVisitor{public:void VisitASuite( const ASuite& );void VisitSimpleTypeId ( const SimpleTypeId & );};voidSimpleTypeIdPrinter::VisitASuite(const ASuite & s){VisitSimpleTypeDefs( s.declarationsPart().definitions().ts_TypeDefs().simpleTypeDefs());}voidSimpleTypeIdPrinter::VisitSimpleTypeId( constSimpleTypeId & id ){cout << "Id: "<< id.simpleTypeIdentifier()<< endl;}Finally, you may combine several visitors into one visitor, thus avoiding multiple passes when processing a suite. This implies that you define several classes which are not truly visitors, and define a inherited class from AccessVisitor which calls methods in these classes.
Two objects driven by a visitor, thus performing two passes on one traversal.
class IdOperation{public:virtual void AtIdentifier(const Identifier&) = 0;};// A IdOperationclass IdCounter : public IdOperation{public:IdCounter( ) : _count( 0 ) { }void AtIdentifier( const Identifier & id ){ _count++; }~IdCounter( ) { cout << _count << endl; }private:unsigned int _count;};// Another IdOperationclass IdPrinter : public IdOperation{public:void AtIdentifier( const Identifier & id ){ cout << id << endl; }};// A class which drives up to IdOpDriverMax// IdOperationsconst int IdOpDriverMax = 10;class IdOpDriver : public AccessVisitor{public:IdOpDriver() : _ops_used(0) { }void VisitIdentifier( const Identifier & id ) {for (unsigned int op = 0 ; op < _ops_used; ++op)_ops[op].AtIdentifier( id );}void AddIdOp( IdOperation * op ){ _ops[_ops_used++] = op; }private:IdOperation _ops[IdOpDriverMax];unsigned int _ops_used;};// Main routine which opens a suite and applies two// IdOperations.int main( int argc, char ** argv ){AccessSuite suite;if ( suite.open( argv[1] ) ) {IdCounter counter;IdPrinter printer;IdOpDriver driver;driver.AddIdOp( &counter );driver.AddIdOp( &printer );driver.Visit( suite );suite.close( );}return 0;}
http://www.ibm.com/rational |
![]() |
![]() |
![]() |
![]() |