Introducing ABAP Objects
ABAP Objects, the object-oriented (OO) extension to the ABAP language, is available with releases 4.5 and 4.6. Release 4.6 adds inheritance, nested interfaces, and dynamic method invocation. In this article, as two of the developers of this new extension, we’ll take you through an introduction to ABAP Objects and give you a comprehensive example (The code for the example can be tested and debugged in DEMO_ABAP_OBJECTS in R/3 release 4.6 or higher).
ABAP Objects is a nearly 100 percent upward-compatible extension of ABAP that includes a full set of OO features. We left out some obsolete language elements in the OO context within classes (so it is not truly 100 percent compatible), but you can use objects in all contexts without any restrictions.
We created ABAP Objects because:
- The business object repository (BOR) already presented an OO view of the system to the outside, and we wanted a common programming model for both outside and inside.
- We wanted the potential benefits of objects within R/3, including better control of complexity, a better means for encapsulation, extensibility, and reuse, and a language basis for patterns and frameworks.
- We wanted seamless integration with external object models (DCOM and CORBA).
- We needed objects to be the foundation for a new GUI programming model (to be completed in release 5.0).
At the beginning of the ABAP Objects project, we faced a fundamental question: Should we add OO features to the existing ABAP language, invent a completely new language, or integrate an existing OO language into R/3? We opted to integrate OO features into the existing ABAP language to create ABAP Objects for several reasons:
- It meant we would immediately inherit all the other features of the R/3 infrastructure such as software logistics, portable database access, TP monitor capabilities, and all database buffering and scalability.
- Certain features, such as persistence, transactions, events, and GUI frameworks, are hard to add on top of a language. This results in lots of generated code. To support these concepts, you must have your own compiler or interpreter and runtime, ruling out most off-the-shelf languages.
- Our target was a language for business applications. We wanted it to be simpler than Java and C++ and to leave out complex concepts lacking in benefits.
- By integrating the concepts of OO languages—as opposed to using a specific OO language—into ABAP, we were able to combine the best concepts from these languages and adapt them, when needed, to our specific needs.
Our main design goals were:
- To make ABAP Objects as simple as possible
- To use only proven OO concepts
- To comply with external standards whenever possible (for example, to allow mapping to COM, CORBA, and UML)
- To require much stronger typing (type checking) than traditional ABAP, where type specification is almost always optional.
The Design Environment
When designing ABAP Objects, we faced some special R/3-specific challenges:
- Extreme variability—R/3 is a meta-application that is massively configurable and extendable by five layers.
- R/3 is an interpretive system, so there is never a shutdown-change-recompile-restart cycle.
- Software development logistics allow hundreds of developers to work on the same system parts, and logistics must not be hindered by the language. The change process must be considered and supported by certain language features (mostly resulting in some deliberate deviations from the general strong typing policy). You cannot assume that developers can always perform synchronous global changes in the system.
Some of ABAP Objects’ key design elements include:
- Classes are not structures with methods (as in C++) but a new kind of type.
- Reference semantics for objects. ABAP is completely value-based. There are no references in the language, and a MOVE always copies its values (even with field-symbols). Objects, on the other hand, can only be accessed by references (there are no embedded objects). This results in a clear separation of values and references. An object reference always has reference semantics. This is the only place in ABAP where objects are shared and never copied. Values (the traditional data) are always copied.
- Single inheritance with a separate concept of interfaces. Here we follow a path similar to Java. Most multiple inheritance applications are actually interface cases, and the few extra capabilities of multiple inheritance definitely don’t warrant the complexity this introduces into the language.
- ABAP Objects integrates complex concepts, most notably events and dynamic method invocation. Events are introduced similarly to how they exist in Visual Basic. They are outbound methods that can have parameters. This is a natural model for GUI applications. We also separated the event registration into a separate statement (SET HANDLER), which gives you the flexibility to define all kinds of topologies of sender-to-handler connections (1:1, 1:n, n:1, n:m).
- Of course, ABAP Objects has its own storage management (garbage collection) and a suite of tools such as the Class Builder, Class Browser, and debugger support.
With release 4.6, the ABAP language is pretty much complete with all object components, inheritance, and nested interfaces. Two main areas of ABAP Objects are still under development: A new GUI programming model and GUI design tool, and the Object Services framework that covers persistence, transaction control, and locking. These should be completed by release 5.0.
ABAP Objects Basics
ABAP Objects is based on classes. Classes are pieces of program code that describe objects by defining their components. Typical object components are attributes (data), which describe an object’s state, and methods (functions), which describe an object’s behavior. Objects are instances of classes. Many objects can be created from one class, but each object has its own attributes.
ABAP Objects provides a set of new statements that defines classes and handles objects. These statements can be used in any kind of ABAP program.
Classes, and therefore objects, consist of at least two layers—an inner and an outer layer. The externally visible layer of an object is made up of public components. Public components can be accessed directly by all users and form an object’s external point of contact. Private components are only visible within objects of the same class. The public section usually contains few attributes. The state of an object is generally kept in private attributes and manipulated by public methods. This way an object can ensure its own consistency.
Outside ABAP Objects, the only instances in ABAP are instances of whole ABAP programs such as reports, module pools, or function groups. Each time a program is executed, a program instance is implicitly created, which then runs in a separate ABAP process. Calling an external procedure (a subroutine or a function module) also creates an ABAP program instance, which contains the procedure. However, repeated calls always use the same one instance. Such program instances live as long as the application program is running and cannot be handled explicitly.
With ABAP Objects, it is now possible to explicitly handle instances. The instances of classes, namely objects, are created explicitly with ABAP statements. They have a unique identity (independent of their attribute values) and are addressed by references. They live only as long as they are needed.
Classes. Classes are templates for objects. You can either define a class locally in an ABAP program, or globally in the class library using the Class Builder tool in the ABAP Workbench. The class library is part of the R/3 repository. Class library classes are stored in special programs called class pools. A class pool is automatically generated for each global class that you create with the Class Builder. The Class Builder also generates the coding frame that defines the classes in the class pool. Global classes are visible to all ABAP programs of the R/3 System.
To define local classes in an ABAP program, such as a report or a function group, you must type the corresponding statements manually into the program. A local class is visible only inside the program in which it is defined.
Classes are defined between the CLASS and ENDCLASS statements. A class definition consists of a declaration part, in which the components are defined, and an implementation part, in which the methods are implemented.
Component visibility. Each component must be declared in one of three possible visibility sections. All components declared in the PUBLIC SECTION can be accessed by all clients of the class. All components declared in the PROTECTED SECTION can be accessed in the methods of the class and its subclasses (see inheritance). All components declared in the PRIVATE SECTION can only be accessed in the methods of the class. The public section forms the outer layer, or external interface, of the class. The protected and the private sections form the inner layer. Their components cannot be accessed by external users.
Class components. Possible class components are attributes, methods and events. Events will be explained later in this article.
- Attributes: are the internal data variables within a class. They can have any ABAP data type. We distinguish between instance attributes and static attributes. Instance attributes are declared by DATA and determine the state of an instance. You cannot work with instance attributes without creating an object first. Static attributes are declared by CLASS-DATA and determine the state of a class, which in a way applies to all instances. Static attributes form a data set that is shared by the whole class and all of its objects. You do not need to create an object to work with static attributes.
- Methods: are the class’ procedures. They can access all class attributes and can therefore change the state of an object. They have a parameter interface similar to the interface of function modules. They can have named IMPORTING, EXPORTING, and CHANGING parameters, which can be optional or required and can be passed either by reference or by value. As with attributes, we distinguish between instance methods and static methods. Instance methods are declared by METHODS and can access all the attributes of a class. Static methods are declared by CLASS-METHODS and can only access the static attributes of a class.
Listing 1, defines a class vessel. The components of class vessel are the attributes speed, max_speed, object_count, and id, and the methods constructor, drive, and get_id.
CLASS vessel DEFINITION. PUBLIC SECTION. METHODS: constructor, drive IMPORTING speed_up TYPE i, get_id RETURNING value(id) TYPE i. PROTECTED SECTION. DATA: speed TYPE i, max_speed TYPE i VALUE 100. PRIVATE SECTION. CLASS-DATA object_count TYPE i. DATA id TYPE i. ENDCLASS. CLASS vessel IMPLEMENTATION. METHOD constructor. object_count = object_count + 1. id = object_count. ENDMETHOD. METHOD drive. speed = speed + speed_up. IF speed > max_speed. speed = max_speed. ENDIF. ENDMETHOD. METHOD get_id. id = me->id. ENDMETHOD. ENDCLASS.
Figure 1, page 34, shows how the class vessel is composed by its visibility sections.
Method implementation. Each method declared in the declaration part of a class must be implemented in its implementation part. Each implementation is enclosed between the METHOD and ENDMETHOD statements. You can use almost all ABAP statements available in subroutines or function modules to implement the method, but ABAP Objects does use a stricter syntax in some places to avoid obsolete features. Methods may contain declarations of local data and data type.
Constructors. Implicitly, each class has an instance constructor method with the reserved name constructor and a static constructor method with the reserved name class_constructor. The instance constructor is executed each time you create an object (instance) with the CREATE OBJECT statement, while the class constructor is executed exactly once before you first access a class. The constructors are always present. However, to implement a constructor you must declare it explicitly with the METHODS or CLASS-METHODS statements. An instance constructor can have IMPORTING parameters and exceptions. You must pass all non-optional parameters when creating an object. Static constructors have no parameters.
Objects and object references. Objects are instances of classes. From the user’s point of view, there is almost no difference between creating objects based on global classes and creating them on local classes. The statements for creating and handling objects are exactly the same for both types of classes. Visibility distinguishes between global and local classes. While any program can create objects from classes in the class library, only the defining program can create objects from its own local classes.
Reference variables. Objects live in the internal session of an ABAP program and are accessed only via reference variables. Object reference variables contain references (pointers) to objects and must be declared before creating an object and accessing its components.
To declare a reference variable, you use the new data type REF TO class. Like other variables, reference variables can be components of structures or internal tables. You initialize a reference variable with the CLEAR statement. The initial value of a reference variable is a reference that does not point to an object.
Instances. Once you have declared a reference variable oref with the type of a class, you can create a class instance. Use the statement CREATE OBJECT oref, which creates an instance of the class with the type of oref and places a reference to the new instance into oref. Each CREATE OBJECT statement creates a new object.
You can create any number of instances of the same class in a program. Those instances are fully independent of each other, and they have their own identity and attributes within the program. You can assign references between reference variables using the MOVE statement or pass them as parameters. ABAP Objects’ reference variables are always type-safe in the sense that they can only contain pointers to objects that conform to the interface given by the reference variable’s declaration type. If that check is not possible statically, you can cast reference variables at run time.
Listing 2 declares two reference variables, vessel1 and vessel2, and creates two instances of class vessel with the two reference variables pointing to them. Methods of the objects are then called.
DATA: vessel1 TYPE REF TO vessel, vessel2 TYPE REF TO vessel. DATA vessel_id TYPE i. CREATE OBJECT: vessel1, vessel2. CALL METHOD: vessel1->drive( 50 ), vessel2->drive( 80 ). vessel_id = vessel1->get_id( ). WRITE: / 'Vessel ID is', vessel_id. vessel_id = vessel2->get_id( ). WRITE: / 'Vessel ID is', vessel_id.
Figure 2, page 34, shows the two reference variables, each pointing to an instance of class vessel. The names of the objects are shown in the same format (id<classname>) as the contents of reference variables in the ABAP Debugger. These names cannot be used directly in the program.
Garbage collection. An object is in use as long as there is at least one reference pointing to it. When there are no more references pointing to an object, the memory space occupied by that object can be released. ABAP Objects provides a garbage collector, which ensures that the memory is collected automatically.
Accessing the components of objects. To access an instance component from outside the defining class, you use the object component selector →, which combines the object (reference) with the component name. Similarly, the class component selector ⇒ combines the class with the component name when you access a static component.
To access attributes, you write oref→attr for instance attributes and class⇒attr for static attributes. To call a method, you write CALL METHOD oref→meth for an instance method and CALL METHOD class⇒meth for a static method. CALL METHOD has almost the same syntax as CALL FUNCTION, but ABAP Objects adds functional methods. These are characterized by the fact that besides IMPORTING parameters, they have exactly one RETURNING parameter. This is an advantage because they can be used like an ordinary variable directly in certain expressions. Instead of entering a variable name, you simply write oref→meth(…) or class⇒meth(…) specifying the required IMPORTING parameters within the parentheses. During the execution of the expression the method is evaluated, and the value of the RETURNING parameter is used in the expression.
Inside methods, components of the same class can be addressed directly by their names, where the compiler prepends the self reference ME implicitly. Only in special cases—for example, when an attribute is hidden by a local data object or parameter with the same name—are you required to use just the ME→attr notation to explicitly select the attribute (see an example in the constructor in Listing 3, page 33). ME can also be used when a method wants to pass a reference that points to its own object.
Listing 3. Statements for deriving a subclass.
CLASS ship DEFINITION INHERITING FROM vessel. PUBLIC SECTION. DATA name TYPE string READ-ONLY. METHODS: constructor IMPORTING name TYPE string, write, drive REDEFINITION. ENDCLASS. CLASS ship IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor. max_speed = 30. me->name = name. ENDMETHOD. METHOD write. DATA id. id = me->get_id( ). WRITE: / name, 'is vessel', id, 'and has speed', speed. ENDMETHOD. METHOD drive. speed = speed + speed_up. IF speed > max_speed. max_speed = 0. speed = 0. ENDIF. ENDMETHOD. ENDCLASS.
Inheritance. Inheritance allows you to derive new classes from an existing one. The new class inherits all components of the existing class and is known as the subclass. The existing class is known as the superclass. A subclass reuses the code of its superclass, but only the public and protected components of the superclass are visible in its subclasses. You can define additional components in the subclass, making it more specialized than the superclass. A subclass itself can become a superclass of additional new classes. This allows you to introduce several degrees of specialization.
Subclasses. To define a subclass, you use the INHERITING FROM clause in the CLASS statement of the declaration part. ABAP Objects supports single inheritance. Classes can have several direct subclasses, but only a single superclass. A special kind of multiple inheritance in ABAP Objects is provided by interfaces (which we will get to shortly).
When a subclass inherits from a superclass that is itself a subclass of another class, the classes involved form an inheritance tree, which becomes more specialized moving from top to bottom. The components of a superclass are passed on to all subclasses within the tree. The implicit root node of all ABAP Objects inheritance trees is the predefined class OBJECT.
In Listing 3, a subclass ship is derived from superclass vessel. The subclass ship specializes its superclass by adding a new attribute name and a new method write. Furthermore, class ship has its own constructor and redefines the method drive.
Redefinition. In subclasses, you can make the public and protected instance methods of all preceding superclasses specialized by redefining them using the REDEFINITION clause of the METHODS statement. You cannot change the interface of a redefined method. Redefined methods are merely implemented differently under the same name. Within a redefined method, you can use the pseudoreference SUPER to access the method with the same name in the superclass. It is always a good idea to call the superclass method that you are redefining before specializing it.
If you define an instance constructor in a subclass, you must call the instance constructor of the superclass by using CALL METHOD super→constructor in its implementation. Before the call, the subclass constructor behaves like a static method. It can access only static attributes in that part of the constructor. After the call, it behaves like an instance method and can also access instance attributes. This is to ensure that the superclass is completely initialized before the subclass accesses its attributes.
Abstract and final. ABAP Objects also provides ABSTRACT and FINAL clauses like other OO languages. With the ABSTRACT and FINAL clauses for the METHODS and CLASS statements, you can define abstract and final methods or classes. When a method is declared abstract, it doesn’t have an implementation in this class, but it expects a subclass to provide its (specialized) implementation. When a class has one or more abstract methods, the class as a whole becomes abstract or incomplete. Therefore, you cannot create abstract class objects. The FINAL clause allows you to restrict inheritance. Final methods cannot be redefined in a subclass, and final classes cannot have any further subclasses.
Polymorphism. Polymorphism is a very important OO concept. Inheritance provides one means of polymorphism. Its effect is best seen when we consider using objects via a reference variable. Polymorphism means that a reference variable with the type REF TO vessel can always contain references to instances of any subclass of that class vessel, such as to an instance of ship or boat. Since a subclass has at least all the components of all its superclasses, you can access all the components of vessel in any subclass. By using a higher level reference, you simply ignore the components added in subclasses.
However, the most important part of polymorphism in terms of inheritance is the methods. Consider the example above: A class ship is inherited from class vessel and has redefined the method drive. When we now have a pointer to an instance of ship in a reference variable of type REF TO vessel, and we call the method drive, the drive method of the class ship is executed, even though the reference to that instance is of type REF TO vessel.
The general rule is: When calling a method, the most specialized redefinition (in a subclass) gets called. This method can then directly call its superclass implementation. Thus, with inheritance, a method call goes as far down as possible, and your own code must call the implementations of this method upwards. In ABAP Objects, you are only allowed to call a method’s direct predecessor implementation. You can only go one level up with CALL METHOD SUPER→m, and you can only call your own method and not other methods of your superclass. (These restrictions are not for technical reasons but to guide the users of ABAP Objects towards proper use of inheritance.)
Reference variables can always hold reference to subclass instances. In particular, the root class OBJECT can hold references to any object.
Using the normal method call or attribute access notation, you can only access components of the class that was used to define the reference variable. Only a dynamic invoke allows the user to access statically unknown methods. For example, if a subclass ship had an additional method sink, you could not call it statically through a reference of type REF TO vessel, but you could call it using the dynamic method call.
Listing 4 declares two reference variables, one of type vessel and one of type ship. A class ship object is created. The IMPORT parameter of its constructor is filled. The object can be accessed by both reference variables. In both cases, the method drive that is declared in class vessel is called. But you cannot call the method write with reference variable vessel.
DATA: vessel TYPE REF TO vessel, ship TYPE REF TO ship. CREATE OBJECT ship EXPORTING name = 'Titanic'. CALL METHOD ship->drive( 20 ). MOVE ship TO vessel. CALL METHOD vessel->drive( 10 ). CALL METHOD ship->write.
The implicit calling of methods that are redefined in subclasses means that, with the superclass’s interface, a method call accesses different method implementations in different subclasses. This has an important consequence: A subclass should never change the semantics of a method via redefinition. A subclass must always do more than the superclass but never take anything away.
Interfaces. The public components of a class define the external point of contact for the class. They define the semantic interface specific to this class. As an illustration, a Customer class would have a CustomerId, and an Order class would have an OrderId as well as lots of specific methods.
However, there are many cases when we want another kind of polymorphism, one that is independent of inheritance. Consider the following examples:
The ArchiveManager class wants to define what it needs in order to archive a class in a special interface and then access all different classes uniformly through that interface. It doesn’t care what specific class it is accessing. It only cares about the archiving aspect. All classes that want to be archived must implement the IF_Archive interface. In the same way, a WorkflowManager class would define an IF_Workflow interface, and all classes that want to participate in the workflow must implement this interface.
The general concept of interfaces is this: An interface is a separate language construct that is allowed to define components (such as in the public section of a class) but without implementation. Classes can implement one or more interfaces in their public section, thereby extending this section.
Interfaces can also be used to define reference variables of type REF TO interface. These interface references only show those components that are defined in the interface, regardless of the implementing class. When a class implements an interface, we can get a reference to any implemented interface by way of simple assignment of the form iref = oref.
Interfaces in ABAP Objects. Like classes, you can define interfaces globally in the class library or locally within an ABAP program. Interfaces are defined between the INTERFACE and ENDINTERFACE statements. They can contain the same components as classes. An interface’s methods are not implemented in the interface itself, but must be implemented in the classes that implement the interface. You do not have to assign the interface components to a visibility area. Instead, all components automatically belong to the public section of the class implementing the interface.
You implement an interface in a class by using the statement INTERFACES in the public section, which causes the components of the interface to be added to the public components of that class, all with names of the form intf~comp. All components of an implemented interface appear within the class with the name prefix intf~. To access a component comp of an interface within a class or when using a class reference, you must use the name intf~comp. However, when using an interface reference, you can specify the interface components directly, since the interface reference only shows the components of that interface. While we use the names intf~comp inside the implementing class, the users of the interface just write iref→comp.
Implemented interface components are fully equivalent to normal class components. They extend the outer layer (public section) of the class. All users can access both the class-specific public components as well as the components of the interface.
One class can implement several interfaces, and each interface can be implemented by many classes. When a class implements an interface, it immediately has its attributes and events (see Listing 5, page 36), but it must implement all methods of the implemented interfaces in its implementation part. The interface’s methods can be implemented differently in each implementing class. Therefore, in addition to inheritance, interfaces provide another means of polymorphism in ABAP Objects. As for redefined methods with inheritance, the implementation of an interface method should confirm to the semantics defined in the interface.
INTERFACE status. METHODS write. ENDINTERFACE. CLASS ship DEFINITION INHERITING FROM vessel. PUBLIC SECTION. INTERFACES status. ... ENDCLASS. CLASS ship IMPLEMENTATION. ... METHOD status~write. DATA id. id = me->get_id( ). WRITE: / name, 'is vessel', id, 'and has speed', speed. ENDMETHOD. ... ENDCLASS. CLASS coast_guard DEFINITION. PUBLIC SECTION. INTERFACES status. ALIASES write FOR status~write. PRIVATE SECTION. DATA caller TYPE string. ENDCLASS. CLASS coast_guard IMPLEMENTATION. METHOD status~write. IF caller IS INITIAL. WRITE: / 'Coast guard received no call'. ELSE. WRITE: / 'Coast guard received a call from', caller. ENDIF. ENDMETHOD. ENDCLASS.
Listing 5 defines an interface status. It contains one method, write. The class ship replaces its own method write by implementing the interface status. Another class, coast_guard, is defined that also implements status. Both classes implement the interface method status~write.
- Nested interfaces: By using the INTERFACES statement within the interface definition, you can define nested interfaces. When an interface contains a nested component interface, this inner interface appears as one component. The components of the contained interface are not automatically visible in the enclosing interface. To make a component of a contained interface component visible on the higher (enclosing) level, you can use the ALIASES statement.
- Interface references: Besides reference variables declared with respect to a class, ABAP Objects also provides reference variables declared with respect to an interface. Those interface reference variables expose only the components defined in the interface, regardless of the implementing class.
Listing 6, page 36, declares a variable status and an internal table status_tab as interface reference variables. The contents of two class reference variables, pointing to objects of ship and coast_guard, are appended to that internal table. By looping on the internal table, the interface method write is accessed in both objects. Listing 6 shows how objects of two different classes are accessed by reference variables of one kind. Although ships and coast guards do not have much else in common, the user can expect the same semantics from the interface method write.
DATA: status TYPE REF TO status, status_tab TYPE TABLE OF REF TO status. DATA ship TYPE REF TO ship. DATA station TYPE REF TO coast_guard. CREATE OBJECT ship EXPORTING name = 'Titanic'. APPEND ship TO status_tab. CREATE OBJECT station. APPEND station TO status_tab. LOOP AT status_tab INTO status. CALL METHOD status->write. ENDLOOP.
Figure 3, page 34, shows the internal table of interface references pointing to objects of different classes that implement a common interface.
Events. Events generally announce that an object’s state has changed or that something happened that may be of interest to others. They are like outbound method calls and enable a different kind of coupling between objects. They are especially useful in a GUI environment, but are also good for loosely coupling subsystems and for workflow.
The basic concept of methods is: When one object A calls a method of another object B, A must know B. A must have an attribute that is a reference to B.
With events, the situation is different: They work by publish and subscribe. One class A defines an event e that may be of interest to other classes/objects. When class B wants to react to the event e of A, it defines a handler method h for that event. At run time, an object of B registers its method h as a handler for that event of a sender object of class A. When the object A now raises event e, all registered handlers for that event are notified or called. The key issue is that a handler can be attached to do more without changing the sender’s code.
- Events in ABAP Objects: Events are another kind of component in classes. They are declared in the declaration part of a class and raised in its methods. You declare events by using the statements EVENTS for instance events and CLASS-EVENTS for static events. Events can have EXPORTING parameters to pass parameters from the triggering object to the handler. Each instance event has an additional implicit parameter called SENDER. The SENDER data type is a reference variable to the respective sender class.
Static events can be raised in any method of the declaring class, whereas instance events can only be raised in instance methods. You raise an event in a method using the RAISE EVENT statement, and you pass arguments using the EXPORTING clause. For instance events, the system automatically passes the implicit parameter SENDER,which is a reference pointing to the object raising the event.
Any class may contain event handler methods for events of other classes. The event handler method signature (names and types of parameters) is not repeated but is taken from the event to be handled. However, the event handler method does not have to accept and use all of the parameters that the event defines. An event handler method can accept the implicit parameter SENDER like any other IMPORTING parameter, allowing it to access the triggering instance. The declaration of events and respective event handler methods in classes constitutes the static part of publish and subscribe.
Listing 7, page 38 declares an event emergency_call in class ship. If the attribute speed becomes higher than max_speed in method drive, the event is raised. A method receive is declared as an event handler in class coast_guard.
CLASS ship DEFINITION INHERITING FROM vessel. PUBLIC SECTION. ... EVENTS emergency_call. ... ENDCLASS. CLASS ship IMPLEMENTATION. ... METHOD drive. ... IF speed > max_speed. ... RAISE EVENT emergency_call. ENDIF. ENDMETHOD. ... ENDCLASS. CLASS coast_guard DEFINITION. PUBLIC SECTION. ... METHODS receive FOR EVENT emergency_call OF ship IMPORTING sender. ... ENDCLASS. CLASS coast_guard IMPLEMENTATION. ... METHOD receive. caller = sender->name. CALL METHOD write. ENDMETHOD. ... ENDCLASS.
- Handling events: If you declare an event handler method in a class, the instances of the class, or the class itself, are then capable of handling the event. If you want an event handler method to react to an event, you must define at run time the trigger to which you want it to respond with the SET HANDLER statement. It links a list of handler methods to corresponding event triggers—either instance events or static events. The SET HANDLER statement also has an addition ACTIVATION, which allows you to register and deregister handlers dynamically. Triggering events in methods and registering event handler methods at run time constitutes the dynamic part of publish and subscribe.
Listing 8 registers the method receive in an instance of class coast_guard as a handler for the event emergency_call in an instance of class ship.
DATA: ship TYPE REF TO ship, station TYPE REF TO coast_guard. CREATE OBJECT: ship EXPORTING name = 'Titanic'. station. SET HANDLER station->receive FOR ship. DO 5 TIMES. CALL METHOD ship->drive( 10 ). ENNDO.
For each SET HANDLER statement, the system creates an entry in an event handler table (see Figure 4, page 38), where a handler table belongs to each instance or class that can trigger instance or static events. It is invisible to the user and contains the names of the handler methods and references to the registered handling instances. When an event is triggered, the system searches the event handler table of the corresponding object or class and executes the listed methods in their instances in the case of instance handler methods, or classes in the case of static handler methods. You can delete single entries from the handler table using the ACTIVATION addition of the SET HANDLER statement. If the triggering instance is deleted by the garbage collector, the entire handler table, including all its references, is deleted.
A reference to an instance in a handler table counts as a use of the instance, just as a reference in a reference variable does. Handler table entries, therefore, affect the lifetime of objects. This means that in our example, the instance j<coast_guard> is not deleted by the garbage collector as long as it is registered for event handling, even if the reference variable station is cleared.
Finally, events, as well as their handler methods, can also be defined in interfaces. Additionally, there are some powerful mass registration variants to register a handler for all instances of a class and all classes implementing a certain interface.
Jùrgen Heymann is senior developer in the SAP ABAP Language Group. He is a key architect in the ABAP Objects project. You can reach him at firstname.lastname@example.org.
Horst Keller is senior technical writer in the SAP ABAP & GUI Group. He documents the ABAP language with an emphasis on ABAP Objects. He also develops and teaches classes on ABAP programming. You can reach him at email@example.com.