Monday, October 13, 2014

OO Programming with ABAP Objects: Interfaces

Throughout the course of this blog series, we have covered the basic cornerstones of object-oriented programming including:



In this final installment of the series, we will expand upon the concept of inheritance/polymorphism by introducing you to the concept of interfaces.


Why do we need interfaces?


In my previous OO Programming with ABAP Objects: Polymorphism, we explored the notion of interface inheritance and showed you how to use it to implement polymorphic designs. Here, the basic premise is that since a subclass inherits the public interface of its superclass, you can invoke methods on an instance of a subclass in exactly the same way that you call them using an instance of the superclass. As we learned, you can leverage this functionality to develop generic methods that can work with an instance of the superclass or any of its subclasses. This is all fine and well when you're working with classes that fit neatly into a particular inheritance model. But what happens when you want to plug in functionality from a class that already has an inheritance relationship defined?

In some programming languages, it is possible to define multiple inheritance relationships in which a given class can inherit from several parent classes. For instance, in the UML class diagram below, class D inherits from classes B and C. Though the concept of multiple inheritance may sound appealing on a conceptual level, it can cause some serious problems on an implementation level. Looking at the UML class diagram below, consider the inheritance of method "someMethod()" for class D. Here, let's assume that classes B and C have overridden the default implementation of this method from class A. Based on this, which implementation of method "someMethod()" does class D inherit: the one from class B or class C? In object-oriented programming parlance, this conundrum is referred to as the diamond problem.

Diamond Problem

Rather than try and tackle multiple inheritance issues such as the diamond problem, the designers of the ABAP Objects language elected to adopt a single inheritance model. This implies that a class can only inherit from a single parent class. This does not mean, however, that you cannot implement multiple inheritance in ABAP. Rather, you simply must go about defining it in a different way using interfaces.

In order to explain the concept of interfaces, it is helpful to see an example of how they are used in code. Consider the LIF_COMPARABLE interface shown below. This interface defines a single method called "compare_to()" that returns an integer indicating whether or not an object is less than, greater than, or equal to another object of the same type. As you can see, we have only defined the method here; there is no implementation provided. Indeed, you are not even allowed to provide implementations within an interface definition.

INTERFACE lif_comparable.
METHODS:
compare_to IMPORTING im_object TYPE REF TO object,
RETURNING VALUE(re_result) TYPE i.
ENDINTERFACE.

Looking at the definition of the LIF_COMPARABLE interface above, you might be wondering why we would want to bother defining an interface. After all, they don't anything particularly exciting. Still, much like classes, it does encapsulate a unique concept: comparability. Comparability is a feature that we would like to implement in a number of different classes. In fact, defining comparability in a common interface enables us to develop generic algorithms for sorting objects, etc. The question is how. Since many of the classes we want to implement this with likely have pre-existing inheritance relationships, we can't define the comparison functionality in a common superclass. However, we can model this functionality in an interface.

Taking our comparability example a step further, let's imagine that we want to define a sort order for a set of customer objects of type LCL_CUSTOMER. For the purposes of our discussion, let's assume that class LCL_CUSTOMER inherits from a base business partner class called LCL_PARTNER. In order to assume the comparability feature, LCL_CUSTOMER also implements the LIF_COMPARABLE interface as shown below.

CLASS lcl_customer DEFINITION
INHERITING FROM lcl_partner.
PUBLIC SECTION.
INTERFACES: lif_comparable.
"Other declarations here...
ENDCLASS.

CLASS lcl_customer IMPLEMENTATION.
METHOD lif_comparable~compare_to.
"Implement comparison logic here...
ENDMETHOD.
ENDCLASS.
Looking at the code excerpt above, you can see that we have split class LCL_CUSTOMER into two dimensions: a customer is a partner; but it is also comparable. This means that we can substitute instances of class LCL_CUSTOMER anywhere that the interface type LIF_COMPARABLE is used.

Now that you have a feel for how interfaces are used, let's attempt to define interfaces a little more formally. An interface is an abstraction that defines a model (or prototype) of a particular entity or concept. As you saw above, you don't define any kind of implementation for an interface; that is left up to implementing classes. Once a class implements an interface, it fulfills the requirements of an inheritance relationship with the interface. In this way, you can implement multiple inheritance using interfaces. Indeed, classes are free to implement as many interfaces as they wish.


How can I use interfaces in my own designs?


Hopefully by now you can see the power of interfaces, but you may be unsure of how to use them in your own designs. In these early stages of development, it is helpful to look around and see how others are making use of interfaces. In particular, we can look to see how SAP uses interfaces in various development objects. Some of the more common places where interfaces are used extensively by SAP include:



  • The iXML Library used to parse XML in ABAP.

  • The ABAP Object Services framework that enables object-relational persistence models.

  • The Web Dynpro for ABAP (WDA) context API.

  • Business Add-Ins (BAdIs)

  • The Internet Communication Framework (ICF) used to send and receive HTTP request messages.

If you have ever worked with BAdIs before, then perhaps you may have interacted with interfaces without even realizing it. BAdIs are a type of customer enhancement in which customers can implement a "user exit" that supplements core behavior with custom functionality. The screenshot below shows the definition of a BAdI called "CTS_REQUEST_CHECK". This BAdI is used to validate a Change and Transport System (i.e. CTS) transport request at various important milestones. On the Interface tab, notice the interface name "IF_EX_CTS_REQUEST_CHECK". This interface defines the methods "check_before_creation()", etc. shown below. Whenever we create a BAdI implementation for "CTS_REQUEST_CHECK", the system will generate a class that implements this interface behind the scenes. At runtime, the CTS system will invoke these methods polymorphically to implement the desired user exit behavior.

BAdI Definition for CTS_REQUEST_CHECK

The BAdI example above provides us with some useful observations about interfaces:



  1. Interfaces are particularly well suited to modeling behavior. In other words, while classes are often representation of nouns, interfaces can often be used to supplement these core entities with different types of behavior, etc.

  2. Interfaces make it possible to implement polymorphism in a lot of different ways. For example, if a pre-existing class contained functionality to handle CTS request milestones, then we could implement the IF_EX_CTS_REQUEST_CHECK interface in that class rather than reinventing the wheel.

  3. Interfaces allow you to further separate the API interface from its underlying implementation.

Based on these observations, we would offer the following rule of thumb:  when developing your OO designs, try and represent your core API using interfaces. This step helps ensure that your design remains flexible over time. An excellent example of this is the iXML Library used to process XML in ABAP. The only concrete class provided in the iXML Library is the CL_IXML factory class - everything else is interface-driven. This abstraction makes it possible for SAP to neatly swap XML parser implementations behind the scenes without anyone knowing the difference. Similarly, if your core API is represented using interfaces, you have much more flexibility at the implementation layer. Over time, you'll thank yourself for putting in the effort up front.

An excellent resource for coming up to speed with interfaces is the classic software engineering text Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). This book allows you to enter the mind of object-oriented pioneers who have documented many useful OO design patterns in an easy-to-read catalog-based format. Digging into these designs, you'll see how interfaces can be used to implement certain types of flexibility that simply cannot be realized with basic inheritance. You'll especially appreciate the ABAP Objects implementation when you see how the authors struggle to implement certain functionality in C++ (which does not support interfaces).


Closing Thoughts and Next Steps


I hope that you have enjoyed this blog series as much as I have enjoyed writing it. Thanks to everyone for their kind and useful feedback; it is much appreciated. In many ways, this series barely scratches the surface of the possibilities of OO programming. If you are interested in learning more, might I offer a shameful plug for my book Object-Oriented Programming with ABAP Objects (SAP Press, 2009). Here, I cover these topics (and more) in much more depth. Best of luck with your object-oriented designs!

Object-Oriented Programming with ABAP Objects

OO Programming with ABAP Objects: Polymorphism

In my previous OO Programming with ABAP Objects: Inheritance, we learned about inheritance relationships. As you may recall, the term inheritance is used to describe a specialization relationship between related classes in a given problem domain. Here, rather than reinvent the wheel, we define a new class in terms of a pre-existing one. The new class (or subclass) is said to inherit from the existing class (or parent class). Most of the time, when people talk about inheritance, they focus their attention on code reuse and the concept of implementation inheritance. Implementation inheritance is all about reducing redundant code by leveraging inherited components to implement new requirements rather than starting all over from scratch.

One aspect of inheritance relationships that sometimes gets swept under the rug is fact that subclasses also inherit the interface of their parent classes. This type of inheritance is described using the term interface inheritance. Interface inheritance makes it possible to use instances of classes in an inheritance hierarchy interchangeably – a concept that is referred to as polymorphism. In this blog, we will explore the idea of polymorphism and show you how to use it to develop highly flexible code.


What is Polymorphism?


As you may recall from my last OO Programming with ABAP Objects: Inheritance, one of the litmus tests for identifying inheritance relationships is to ask yourself whether or not a prospective subclass fits into an “Is-A” relationship with a given parent class. For example, a circle is a type of shape, so defining a “Circle” class in terms of an abstract “Shape” class makes sense. Looking beyond the obvious benefits of reusing any implementation provided in the “Shape” class, let’s think about what this relationship means from an interface perspective. Since the “Circle” class inherits all of the public attributes/methods of the “Shape” class, we can interface with instances of this class in the exact same way that we interface with instances of the “Shape” class. In other words, if the “Shape” class defines a public method called “draw()”, then so does the “Circle” class. Therefore, the code required to call this method on instances of either class is exactly the same even if the underlying implementation is very different.

The term polymorphism literally means “many forms”. From an object-oriented perspective, the term is used to describe a language feature that allows you to use instances of classes belonging to the same inheritance hierarchy interchangeably. This idea is perhaps best explained with an example. Getting back to our “Shape” discussion, let’s think about how we might design a shape drawing program. One possible implementation of the shape drawing program would be to create a class that defines methods like “drawCircle()”, “drawSquare()”, etc. Another approach would be to define a generic method called “draw()” that uses conditional statements to branch the logic out to modules that are used to draw a circle, square, etc. In either case, there is work involved whenever a new shape is added to the mix. Ideally, we would like to decouple the drawing program from our shape hierarchy so that the two can vary independently. We can achieve this kind of design using polymorphism.

In a polymorphic design, we can create a generic method called “draw()” in our drawing program that receives an instance of the “Shape” class as a parameter. Since subclasses of “Shape” inherit its interface, we can pass any kind of shape to the “draw()” method and it can turn around and use that shape instance’s “draw()” method to draw the shape on the screen. In this way, the drawing program is completely ignorant of the type of shape it is handling; it simply delegates the drawing task to the shape instance. This is as it should be since the Shape class already knows how to draw itself. Furthermore, as new shapes are introduced into the mix, no changes would be required to the drawing program so long as these new shapes inherit from the abstract “Shape” class.

This generic approach to programming is often described using the term design by interface. The basic concept here is to adopt a component-based architecture where each component clearly defines the services (i.e. interface) they provide. These interfaces make it easy for components to be weaved together into larger assemblies. Here, notice that we haven’t said anything about how these components are implemented. As long as the components implement the services described in their interface – it really doesn’t matter how they are implemented. From an object-oriented perspective, this means that we can swap out a given object for another so long as they share the same interface. Of course, in order to do so, we need to be able to perform type casts and dynamic method calls.


Type Casting and Dynamic Binding


Most of the time, whenever we talk about the type of an object reference variable in ABAP Objects, we are talking about its static type. The static type of an object reference variable is the class type used to define the reference variable:

DATA: lr_oref TYPE REF TO zcl_shape.

An object reference variable also has a dynamic type associated with it. The dynamic type of an object reference variable is the type of the current object instance that it refers to. Normally, the static and dynamic type of an object reference variable will be the same. However, it is technically possible for an object reference variable to point to an object that is not an instance of the class type used to define the object reference. For example, notice how we are assigning an instance of the ZCL_CIRCLE subclass to the lr_shape object reference variable (whose static type is the parent class ZCL_SHAPE) in the code excerpt below.

DATA: lr_shape  TYPE REF TO zcl_shape,
lr_circle TYPE REF TO zcl_circle.

CREATE OBJECT lr_shape.
CREATE OBJECT lr_circle.
lr_shape = lr_circle.

This kind of assignment is not possible without a type cast. Of course, you can’t perform a type cast using just any class; the source and target object reference variables must be compatible (e.g., their static types must belong to the same inheritance hierarchy). In the example above, once the assignment is completed, the dynamic type of the lr_shape reference variable will be the ZCL_CIRCLE class. Therefore, at runtime, when a method call such as “lr_shape->draw( )” is performed, the ABAP runtime environment will use the dynamic type information to bind the method call with the implementation provided in the ZCL_CIRCLE class.

The type cast above is classified as a narrowing cast (or upcast) as we are narrowing the access scope of the referenced ZCL_CIRCLE object to the components defined in the ZCL_SHAPE superclass. It is also possible to perform a widening cast (or downcast) like this:

DATA: lr_shape  TYPE REF TO zcl_shape,
lr_circle TYPE REF TO zcl_circle.
CREATE OBJECT lr_shape TYPE zcl_circle.
lr_circle ?= lr_shape.

In this case, we are using the TYPE addition to the CREATE OBJECT statement to create an instance of class ZCL_CIRCLE and assign its reference to the lr_shape object reference variable. Then, we use the casting operator (“?=”) to perform a widening cast when we assign the lr_shape object reference to lr_circle. The casting operator is something of a precaution in many respects as widening casts can be dangerous. For instance, in this contrived example, we know that we are assigning an instance of ZCL_CIRCLE to an object reference variable of that type. On the other hand, if the source object reference were a method parameter, we can’t be sure that this is the case. After all, someone could pass in a square to the method and cause all kinds of problems since class ZCL_CIRCLE may well define circle-specific methods that cannot be executed against an instance of class ZCL_SQUARE.


Implementing Polymorphism in ABAP


Now that you have a feel for how type casting works in ABAP Objects, let’s see how to use it to implement a polymorphic design in ABAP. The example code below defines a simple report called ZPOLYTEST that defines an abstract base class called LCL_ANIMAL and two concrete subclasses: LCL_CAT and LCL_DOG. These classes are used to implement a model of the old “See-n-Say” toys manufactured by Mattel, Inc. This model is realized in the form of a local class called LCL_SEE_AND_SAY. If you have never played with a See-n-Say before, its interface is very simple. In the center of the toy is a wheel with pictures of various animals. When a child can positions a lever next to a given animal, the toy will produce the sound of that animal. In order to make the See-n-Say generic, we define the interface of the “play()” method to receive an instance of class LCL_ANIMAL. However, in the START-OF-SELECTION event, you’ll notice that we create instances of LCL_CAT and LCL_DOG and pass them to the See-n-Say. Here, we didn’t have to perform an explicit type cast as narrowing type casts are performed implicitly in method calls. Furthermore, since the LCL_CAT and LCL_DOG classes inherit the methods “get_type()” and “speak()” from class LCL_ANIMAL, we can use instances of them in the LCL_SEE_AND_SAY generically.

REPORT zpolytest.

CLASS lcl_animal DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: get_type ABSTRACT,
speak ABSTRACT.
ENDCLASS.

CLASS lcl_cat DEFINITION
INHERITING FROM lcl_animal.
PUBLIC SECTION.
METHODS: get_type REDEFINITION,
speak REDEFINITION.
ENDCLASS.

CLASS lcl_cat IMPLEMENTATION.
METHOD get_type.
WRITE: 'Cat'.
ENDMETHOD.

METHOD speak.
WRITE: 'Meow'.
ENDMETHOD.
ENDCLASS.

CLASS lcl_dog DEFINITION
INHERITING FROM lcl_animal.
PUBLIC SECTION.
METHODS: get_type REDEFINITION,
speak REDEFINITION.
ENDCLASS.

CLASS lcl_dog IMPLEMENTATION.
METHOD get_type.
WRITE: 'Dog'.
ENDMETHOD.

METHOD speak.
WRITE: 'Bark'.
ENDMETHOD.
ENDCLASS.

CLASS lcl_see_and_say DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
play IMPORTING im_animal
TYPE REF TO lcl_animal.
ENDCLASS.

CLASS lcl_see_and_say IMPLEMENTATION.
METHOD play.
WRITE: 'The'.
CALL METHOD im_animal->get_type.
WRITE: 'says'.
CALL METHOD im_animal->speak.
ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
DATA: lr_cat TYPE REF TO lcl_cat,
lr_dog TYPE REF TO lcl_dog.

CREATE OBJECT lr_cat.
CREATE OBJECT lr_dog.

CALL METHOD lcl_see_and_say=>play
EXPORTING
im_animal = lr_cat.
NEW-LINE.
CALL METHOD lcl_see_and_say=>play
EXPORTING
im_animal = lr_dog.
As mentioned earlier, one of the primary advantages of using polymorphism in a design like this is that we can easily plug in additional animals without having to change anything in class LCL_SEE_AND_SAY. For instance, if we want to add a pig to the See-n-Say, we just create a class LCL_PIG that inherits from LCL_ANIMAL and then we can start passing instances of this class to the “play()” method of class LCL_SEE_AND_SAY.


Conclusions and Next Steps


Hopefully by now you are starting to see the benefit of implementing object-oriented designs. In many respects, polymorphism represents one of the major payoffs for investing the time to create an object-oriented design. However, as you have seen, polymorphism doesn't happen by accident. In order to get there, you need to pay careful attention to the definition of a class' public interface, make good use of encapsulation techniques, and model your class relationships correctly.

If the concept of polymorphism seems familiar, it could be that you’ve seen examples of this in other areas of SAP. Perhaps the most obvious example here would be with “Business Add-Ins” (or BAdIs). In my next blog, we will look at how BAdIs use interfaces to implement polymorphic designs. Interfaces are an important part of any object-oriented developer’s toolbag; making it possible to extend a class into different dimensions

OO Programming with ABAP Objects: Inheritance

In my OO Programming with ABAP Objects: Encapsulation blog entry, we continued our discussion on OOP by showing how visibility sections could be used to hide implementation details of a class. If you are new to OOP, you might be wondering why you would want to go to such lengths to encapsulate your code. After all, don't we want our software to be open these days? However, the use of implementation hiding techniques does not imply that software must be closed off completely. Rather, we just want to establish some healthy boundaries so that we can give the software some structure. This structure helps the software to gracefully adapt to inevitable changes within a particular area without affecting the overall integrity of the software as a whole.

In this blog entry, I will introduce another core concept of OOP called inheritance. Inheritance describes a relationship between related classes within a particular problem domain. Here, you will see that the use of good encapsulation techniques enables you to expand and enhance the functionality of your applications without having to modify pre-existing classes. In my next blog entry, we will see how these relationships can be exploited using polymorphism.


Generalization and Specialization


During the Object-Oriented Analysis & Design (or OOAD) process, we evaulate real world phenomena and try to simulate the problem domain using classes of objects. Frequently, this classification process goes through several iterations before we get it right. For instance, our first pass through the requirements might generate an OO design with some very basic classes. As we dig deeper, we focus in on determining the roles and responsibilities of each class. Along the way, our classes evolve to become more specialized.

In an ideal world, this analysis process would take place in a vaccuum, allowing us to completely refine our object model before we implement it. Unfortunately, most of us do not have this luxury as we are subject to tight deadlines and limited budgets. Typically, we must draw a line in the sand and build the best software we can given the constraints laid before us. In the past, such hasty development has made it very difficult to adapt the software to implement new functionality, etc. Here, developers would have to decide whether or not they felt like an enhancement could be implemented without jeopardizing the existing production code. If the answer to that question was no, they were forced to cut their losses and try to salvage as much of the code as they could using the "copy-and-paste" approach to building new development objects. Both of these approaches are fraught with risks. Early object-oriented researches recognized that there had to be a better way to extending software.

When you think about it, an enhancement extends or specializes a portion of the system in some way. In an OO system, this implies that we want to enhance or extend certain functionality within one or more classes. Here, we don't really want to modify the existing class(es). Rather, we just want to expand then to handle more specialized requirements, etc. One way to implement this kind of specialization in object-oriented languages is through inheritance.

Inheritance defines a relationship between two classes; the original class is called the superclass (or parent class) and the extended class is called the subclass (or child class). In an inheritance relationship, a subclass inherits the components from its superclass (e.g. attributes, methods, etc.). Subclasses can then build on these existing components to implement additional functionality. When thinking about inheritance, it is important to realize that the relationship is not transient in nature. In other words, a subclass is not just a copy or clone of its superclass. For instance, if you change the functionality in a method of a superclass, that change is reflected in its subclasses (except in the case of overridden methods - more on these in a moment). However, the converse is not true; changes to a subclass are not reflected in its superclass.

In OO parliance, an inheritance relationship is known as an "Is-A" relationship. To explain this relationship, let's consider an example where we have a superclass called "Animal" and a subclass called "Cat". From a code perspective, the "Cat" class inherits the components of the "Animal" superclass. Therefore, as a client looking to use instances of these classes, I see no difference between them. In other words, if the "Animal" superclass defines a method called "eat( )", I can call that same method on an instance of class "Cat". Thus, class "Cat" is an "Animal". This relationship leads to some interesting dynamic programming capabilities that we'll get into in my next blog.

Defining Inheritance Relationships in ABAP Objects

At this point, you're probably ready to dispense with all the theory and get into some live code examples. In the code sample below, you'll see that it is very easy to define an inheritance relationship between two classes.

CLASS lcl_parent DEFINITION.
PUBLIC SECTION.
METHODS: a,
b.

PRIVATE SECTION.
DATA: c TYPE i.
ENDCLASS.

CLASS lcl_child DEFINITION
INHERITING FROM lcl_parent.
PUBLIC SECTION.
METHODS: a REDEFINITION,
d.

PRIVATE SECTION.
DATA: e TYPE string.
ENDCLASS.
As you can see in the example above, you can define an inheritance relationship in a class using the INHERITING FROM addition of the CLASS DEFINITION statement. In the example, class "lcl_child" is a subclass of class "lcl_parent". Therefore, "lcl_child" inherits all of the components defined in class "lcl_parent". However, not all of these components are directly accessible in class "lcl_child". Any component defined in the PRIVATE SECTION of "lcl_parent" cannot be accessed in "lcl_child". However, like any other client of class "lcl_parent", "lcl_child" can access these private components through defined "getter" methods, etc. Sometimes, you may want to share access to a component of a parent class with its subclasses without opening up access completely. In this case, you can define components in the PROTECTED SECTION. This visibility section allows you to define components that can be accessed in a given class and any of its subclasses only.

Once the inheritance relationship is defined, you can access a subclass' inherited public components in the same way you would access them in the parent class. Another thing you might notice in the definition of class "lcl_child" is the REDEFINITION addition added to method "a()". The REDEFINITION addition implies that you want to redefine the way that method "a()" is implemented in the "lcl_child" subclass. Keep in mind that these redefinitions only reshape the code in the IMPLEMENTATION part of the class definition. In other words, you cannot change the interface of the method, etc. - otherwise, you would vioate the "is-a" relationship principal. Inside the redefinition of method "a()" in class "lcl_child", you can reuse the implementation of the superclass using the "super" pseudoreference variable like this: super->a( ). You can think of the super pseduoreference as a sort of built in reference variable to an instance of the subclass' superclass.


Some Final Thoughts


Inheritance relationships can be very powerful, allowing you to reuse software components and improve productivity. However, it is important not to get carried away with trying to define complex inheritance hierarchies, etc. Indeed, many top OO researchers advise against the use of inheritance in many design contexts. The bottom line is that there are places where inheritance works, and places it doesn't.

Another important idea to consider is that inheritance is about more than reuse - it's about building relationships. One nice thing about these relationships is that you can define inheritance hierarchies where you have a family of classes that are interchangeable. You can then design your programs generically using plug-and-play techniques - something we'll learn about in my next blog.

OO Programming with ABAP Objects: Encapsulation

In my OO Programming with ABAP Objects: Classes and Objects blog entry, I introduced the concept of classes and objects, showing you how to create and use both in ABAP Objects. If this is your first exposure to OO programming, you might be wondering what's so great about it. After all, on the surface, a class looks a lot like a function group or subroutine pool. In this blog, we will dig deeper to see where classes differentiate themselves from procedural concepts.


What's Wrong with the Procedural Approach?


One common misconception about OO programming is that it is different from procedural programming in every way - not true. There are many important lessons to be taken from the procedural approach. However, there are certain limitations of this approach that influenced early researchers in their design of the OO paradigm. These limitations are best described with an example. Let's imagine that you want to build a code library to make it easier to work with dates. To do so, you create a function group called ZDATE_API that contains various function modules to manipulate and display dates.

From a data perspective, you have a couple of options. Function groups allow you to define group-specific data objects that can be utilized within function modules (similar to the use of attributes in methods). However, in practice, such data objects can be difficult to use. This is because it is not possible to create "instances" of function groups. For example, in the ZDATE_API function group, I might define a global data object of type SCALS_DATE to keep track of the date being manipulated by the function modules. However, if I need to keep track of multiple dates in my program (e.g. created on date, changed on date, document date, etc.), I need to build an internal table to keep track of each date "instance". I also need to keep track of the key to this table externally - otherwise I have no way of identifying a particular date instance. This limitation causes most developers to keep track of their data objects outside of the function group. If you think back to the last time you tried to call a BAPI and all the data objects you had to define beforehand, you'll appreciate what I mean. We'll explore some of the implications of this approach to data in a moment.

Assuming that we elected to keep track of data separately, let's look at what a function module might look like in our ZDATE_API function group. For the purposes of this discussion, we'll keep it simple and just look at a function module used to set the "day" value of the date:

FUNCTION z_date_set_day.
* Local Interface IMPORTING VALUE (lv_day) TYPE I
*                 CHANGING (cs_date) TYPE SCALS_DATE
*                 EXCEPTIONS invalid_date
DATA: lv_month_end TYPE i. "Last Day of Month

CASE cs_date-month.
WHEN 1.
lv_month_end = 31.
WHEN 2.
...
ENDCASE.

IF iv_day LT 1 OR iv_day GT lv_month_end.
RAISE invalid_date.
ELSE.
cs_date-day = iv_day.
ENDIF.
ENDFUNCTION.

This contrived example simply ensures that we initialize the "day" value of a date to a proper value. Clearly, there are probably better ways to implement something like this, but the point is that we have defined some business rules inside of a function module that is part of an API designed to simplify the way that we work with dates.

Now that we have our function group in place, let's imagine that you are asked to troubleshoot a program that is using your function group to display dates in various formats but it is outputting them incorrectly (e.g., 02/31/2009). At first, you might think that there is a problem with Z_DATE_SET_DAY as the day value is incorrect. However, after further review, you discover that the invalid assignment was made in the program itself. After all, there's nothing stopping a program from changing the day value of a local variable directly. To that program, the day component of the SCALS_DATE structure is nothing more than a 2 digit numeric character with a valid range of 00-99 - the semantic meaning of the day value is defined within the confines of our ZDATE_API function group.

Beyond the issue of data corruption, think about how clumsy the typical function group is. The separation of data and behavior in the ZDATE_API function group limits the usefulness of the abstraction, making the use of the API awkward as we have to pass the SCALS_DATE object back and forth between function calls. This becomes something more than a nuisance when the library expands. For example, think of the impact of expanding this API to support timestamps. A better approach would be to hide this data such that callers don't have to worry about it.


Hiding the Implementation


In programming terms, a function group like ZDATE_API is an abstract data type (or ADT). As the term suggests, an ADT abstracts a particular concept into an easy-to-use data type. Ideally, the creation of a date API would imply that we no longer need to worry about how dates work. Rather, we can leverage the hard work (and testing) that went into the creation of the date API and focus in on other important tasks. However, this is difficult to do if the ADT is not wellencapsulated. The term encapsulate implies that we're combining something into an enclosure (or capsule). In the case of an ADT, we're grouping data and behavior together. Moreover, encapsulation also suggests that we are protecting these resources from external tampering. Initially, most programmers balk at this, preferring to have complete control over all parts of the code. The problem with this is that taking control of any code also implies that you assume some of the risk for ensuring that it operates correctly. In our date example, look at how problematic it was to allow external programs to modify the date structure. Ideally, we would prefer that any modifications to this structure pass through business rule checkpoints to make sure that data is not corrupted.

Encapsulation is a good engineering practice used in many disciplines. For instance, you don't have to know how a car works in order to drive it. Of course, it does help if you have power steering, automatic transmission, etc. These features represent the "interface" that users utilize to interact with the car. ADTs also have an interface (namely the signature of the function modules, method, etc.). Good interface design should make it easy to use an API without diminishing any of its capabilities. Another advantage of this engineering approach is that parts become more interchangeable. For example, imagine that a car manufacturer decides to redesign their fuel injector to improve performance. As long as the new fuel injector has the same interface (e.g. same "hookup"), the manufacturer can swap the parts and nobody's the wiser. In my next two blogs, I'll show how inheritance and polymorphism allows you to do some powerful things here with your OO programs.

Hopefully by now you agree that it is a good idea to group data and behavior together in a class. This, by itself, does not mean that a class is encapsulated. Remember, to achieve this, we must also place a protective capsule around the resources. OO languages such as ABAP Objects allow you to define component visibilities using access specifiers. The following class shows how to define these component visibilities:

CLASS lcl_visible DEFINITION.
PUBLIC SECTION.
DATA: x TYPE i.
PROTECTED SECTION.
DATA: y TYPE i.
PRIVATE SECTION.
DATA: z TYPE i.
ENDCLASS.

As you can see, the components of class lcl_visible are partitioned into three distinct sections: the PUBLIC SECTION, the PROTECTED SECTION, and the PRIVATE SECTION. Components defined in the PUBLIC SECTION are visible everywhere. Components defined in the PRIVATE SECTION are only visible within the class itself. Thus, the only place that you can access the attribute "z" would be inside of an instance method of class lcl_visible. We'll talk about the PROTECTED SECTION when we talk about inheritance.

In this way, we can reproduce our date API in a class like this:

CLASS lcl_date DEFINITION.
PUBLIC SECTION.
METHODS: set_month IMPORTING im_month TYPE i
EXCEPTIONS invalid_date,
set_day   IMPORTING im_day TYPE i
EXCEPTIONS invalid_date,
set_year  IMPORTING im_year TYPE i
EXCEPTIONS invalid_date.
PRIVATE SECTION.
DATA: date TYPE scals_date.
ENDCLASS.

CLASS lcl_date IMPLEMENTATION.
METHOD set_month.
"Implementation of method set_month goes here...
ENDMETHOD.

METHOD set_day.
DATA: lv_month_end TYPE i. "Last Day of Month

CASE date-month.
WHEN 1.
lv_month_end = 31.
WHEN 2.
...
ENDCASE.

IF iv_day LT 1 OR iv_day GT lv_month_end.
RAISE invalid_date.
ELSE.
date-day = iv_day.
ENDIF.
ENDMETHOD.

METHOD set_year.
"Implementation of method set_year goes here...
ENDMETHOD.
ENDCLASS.

Notice that the "date" attribute is defined in the PRIVATE SECTION of the class. Now, any accesses to the "date" attribute must go through public instance methods. This ensures that an external program cannot accidentally (or purposefully) modify the value incorrectly. It also makes the date API easier to use as client programs now only need to define dates like this:

DATA: lr_date TYPE REF TO lcl_date.

With a simple API like this, it's not such a big deal. However, consider how you might implement an API for working with SAP Business Partners, etc. Having the objects keep track of all that data simplifies API use considerably.


Reflections


As you have seen in this blog, encapsulation is a good engineering practice that you can use to develop qualityreusable class libraries. I emphasize reusable here to demonstrate an important point. One of the most common reasons why a library is not reused is because it has too many dependencies. Developing classes using implementation hiding techniques forces you to enter into a mindset whereby classes begin to take on a certain amount of autonomy. In other words, you start to ask yourself questions like "What data does an object of my class need in order to do its job?", etc. Once you have figured this out, you design your interface in such a way as to only provide what the class with what it needs - reducing unnecessary dependencies along the way. The fewer dependencies a class has, the less likely things are to go wrong. And, as we will see in my next blog, it also allows us to expand our libraries in interesting ways without jeopardizing code that has been proven to work.

OO Programming with ABAP Objects: Classes and Objects

Before you can begin to grasp OO-related concepts such as inheritance or polymorphism, you must first understand the fundamental concepts of classes and objects. This article will introduce you to these ideas.


Why do we need classes?


With all of the robust data object types available in the ABAP programming language, you might wonder why we even need classes in the first place. After all, isn't a class just a fancy way of defining a structure or function group? This limiting view has caused many developers to think twice about bothering with OO development. As you will see, there are certain similarities between classes and structured data types, function groups, etc. However, the primary difference with classes centers around the quality of abstraction. Classes group data and related behavior(s) together in a convenient package that is intuitive and easy to use. This intuitiveness comes from the fact that classes are modeled based on real-world phenomena. Thus, you can define solutions to a problem in terms of that problem's domain - more on this in a moment.


Classes and Objects: Defined


Over the years, the term class has been adopted by most OO languages to describe the concept of an abstract type. Here, the use of the word "class" suggests that developers are surveying the problem domain and "classifying" objects within that environment. For example, when developing a financial system, it stands to reason that you might identify classes to represent accounts, customers, vendors, etc. Generally speaking, any noun in a functional specification could suggest a particular object. Of course, it is important to remember that a noun describes a person, place, thing, or idea. In the financial example above, it is easy to identify things like accounts, etc. However, an abstract concept like a dunning process is an equally good candidate for a class.

You can think of a class as a type of blueprint for modeling some concept that you are simulating in a problem domain. Inside this blueprint, you specify two things: attributes and behaviors. An attribute describes certain characteristics of the concept modeled by the class. For instance, if you were creating a "Car" class, that class might have attributes such as "make", "model", "color", etc. Technically, attributes are implemented using various data objects (e.g. strings, integers, structures, other objects, etc.). The behavior of the class is defined using methods. The "Car" class described earlier might define methods such as "drive( )", "turn( )", and "stop( )" to pattern actions that can be performed on a car. The figure below shows an example of the class "Car" with some basic attributes and methods.

Car Class Example

The "Car" class described above only defines a blueprint for building a car - and not the car itself. Taking the blueprint metaphor a step further, consider the difference between a set of blueprints for a house and a house that is built in reference to those blueprints. The blueprints for a house describe basic dimensions, layouts, etc. In other words, they provide instructions for building a house. A homebuilder takes these specifications and builds an instance of this house. An instance of a house has a unique physical address and can be customized to suit a persons preferences. In OO-parlance, an instance of a class is called an object. The relationship between a class and object instances of that class is shown in the figure below.

House Blueprint Example


Defining Classes in ABAP Objects


Now that you know what a class is, let's look at how to define one using ABAP syntax. In ABAP, a class is developed in two parts: a definition section and an implementation section. The definition section for the "Car" class described above looks like this:

CLASS lcl_car DEFINITION.
  PUBLIC SECTION.
    METHODS:
      drive IMPORTING im_driving_speed TYPE i,
      turn IMPORTING im_direction TYPE c,
      stop.
  PRIVATE SECTION.
    DATA:
      make TYPE string,
      model TYPE string,
      color TYPE string,
      driving_speed TYPE i.
ENDCLASS.

In my next blog, we'll go into more details about the PUBLIC SECTION and PRIVATE SECTION specifiers you see in the class definition. For now, it is enough to simply note that we have defined a class called lcl_car that contains methods and attributes. As you can see, attributes are defined using the same data types you would use to define a global or local variable in a non-OO context. Similarly, methods can be defined to have various parameter types just like form routines or function modules.

Presently, our lcl_car class does not have any implementation for the methods drive( ), turn( ), and stop( ). These methods must be implemented in the implementation section of a class definition. The syntax for the implementation section is shown below:

CLASS lcl_car IMPLEMENTATION.
  METHOD drive.
    driving_speed = im_driving_speed.
    WRITE: / 'Current speed is:', driving_speed.
  ENDMETHOD.

  METHOD turn.
    IF im_direction EQ 'L'.
      WRITE: / 'Turning left...'.
    ELSE.
      WRITE: / 'Turning right...'.
    ENDIF.
  ENDMETHOD.

  METHOD stop.
    driving_speed = 0.
    WRITE: / 'Stopped.'.
  ENDMETHOD.
ENDCLASS.
Now that our class is fully defined, we will do something useful with it in the next section.


Instantiating and Using Objects


Once a class is defined, you can create instances of that class in your programs. ABAP does a really nice job of abstracting the instantiation process so creating an object is a breeze. However, the abstraction process implies that you do not have direct access to an object at runtime. Rather, you work with objects via an object reference variablethat points to the object. Object reference variables are defined like this:

DATA: lr_car TYPE REF TO lcl_car.

The previous syntax defines an object reference variable called "lr_car" that references objects of type "lcl_car". Once the reference variable is defined, you can create an object using the following syntax:

CREATE OBJECT lr_car.

The CREATE OBJECT statement asks the ABAP runtime environment to build an object of type lcl_car and store a reference to that dynamically generated object inside the reference variable lr_car. You can think of this reference variable kind of like a remote control that can be used to interface with the object it points to. To "press buttons" on this remote control (i.e. access data, call methods, etc.), you use the object component selector (or "->") operator. The example code below shows how to invoke methods on a generated car object:

lr_car->drive( 55 ).
lr_car->turn( 'R' ).
lr_car->stop( ).

As you can see, one nice thing about objects is that they are really easy to use. Therefore, you don't have to be an OO guru to start using some really handy classes in your programs. Indeed, if you search for classes matching the pattern "CL_ABAP*" in transaction SE24, you will find many useful classes that SAP has provided out of the box with the AS ABAP.


Summary


Hopefully by now you have learned how to create simple classes and use them in your programs. In my next blog, I will show you how to use access specifiers to implement encapsulation and data hiding in your classes.

SAP Certification Exam Structure

Find out why you need SAP Certification, New SAP Exam structure, Levels of certification and all you need to know about SAP Certification

WHY SHOULD ONE GET CERTIFIED?

 Certification benefits for the SAP professional include:

  • Execute your job with improved levels of success and confidence.

  • Offer evidence of your experience and expertise with rigorous testing.

  • Create and provide access to a community of SAP professional-level certified peers.

WHICH CERTIFICATION EXAM SHOULD I APPEAR?

 SAP Certification is divided into three levels based on your experience and depth of the knowledge.

 SAP Tiered Certification

 Associate level (1-3 years of experience)

This certification covers the foundational-level knowledge in an SAP solution. At this level the exam is based mainly on training, but hands-on experience reinforces the knowledge gained from training.

 Professional certification (3-7 years of experience)

This advanced certification requires proven project experience, business process knowledge, and a more detailed understanding of SAP solutions.

 Master certification (under development) (7-10 years of experience)

This certification, under development, involves demonstrating an expert-level understanding of a specific area of SAP software and the ability to drive innovation and solution optimization through in-depth knowledge and vision. Certification at this level requires broad project experience, comprehensive

SAP product knowledge, and the ability to create a future IT vision within complex project environments.

 SAP CERTIFICATION EXAM STRUCTURE

Before you can understand the exam structure for the associate-, professional-,or master-level exam, you must understand the concept of a competency level.

 Competency Level

 Each level of the certification exam is comprised of two or more of the following competency levels:

  • Level A

Articulate, explain, describe, and outline solutions and processes.

  • Level B

Build, implement, configure, model, and troubleshoot solutions and processes.

  • Level C

Conceptualize, blueprint, modify, and optimize integrated solutions and processes.

Each question on the exam will belong to one of these competency levels. The percentages representing the number of questions for each competency level covered by the exam will vary by competency level.

The breakdown for the associate- and professional-level exams is shown below and illustrates how the percentages for each competency level will vary by exam level.



























CompetencyLevelAssociate-LevelPercentageProfessional-LevelPercentage
Articulate, explain, describe, and outline solutions and processesA6020
Build, implement, configure,model, and troubleshoot solutions and processesB4040
Conceptualize, blueprint, modify, and optimize integrated solutions and processesC040

GENERAL INFORMATION ABOUT THE EXAM

 Duration of the Exam:  You will have 3 hours (180 minutes) to take the exam. This is more than enough time to finish the exam.

 About the Questions: The exam will have 80 questions. These questions have a structure just as the exam has a structure

 About the answers: Answers can be in five forms:

  • Multiple response

More than one answer will be correct. If you are presented with this type of answer, you must Identify all correct responses.

  • Multiple choice

Multiple choices (usually four) are provided, and only one answer will be correct.

  • True/false

Only one answer will be true or false.

  • Fill in the blank

The test is online, so you won’t actually be filling in the blank. This answer type will have you fill in the blank in the form of a multiple-choice answer. Only one answer will be correct.

  • Sequence/ranking

This is not used on the actual exam but could be on future exams. This answer type will have you rank or sequence answers in the correct order.

 If you require more information, drop us mail at info@sapconsultancy.in





Source Code Enhancements - Part 5 of the Series on the New EnhancementFramework



In this weblog I want to address several topics that center more or less around creating source code enhancements. At the beginning, I focus on the different use cases in which developers outside of SAP create an enhancement option. In a next step I narrow the scope and ask the question which type of enhancement option you should prefer as an option provider and in which cases a source code enhancement should be your first choice. As I have already stated in another weblog, in general SAP recommends the use of BAdIs. Still the BAdI is no all-purpose weapon. There are situations in which it is better to use source-code enhancements instead. After sketching these situations I will show you how to create an enhancement point, how to implement an enhancement point and how to overwrite an implementation created in another system without modifications.

Why to Define an Enhancement Option as a Developer Outside of SAP - the Different Use-Cases


Let us start by spending some thoughts as to when and why you might want to define an enhancement option as a non-SAP developer. Of course, it should be clear at the outset that in most cases you will implement enhancement options if you are a non-SAP developer. But as you will learn soon, there is one group of non-SAP developers that will take great advantage of defining enhancement options themselves. These are the ones developing solutions that should be enhanced by somebody else later. I will treat this group in the first use case. In contrast, the second use case is not confined to a particular group, but to any developer who is interested in keeping an unavoidable modification as small as possible.

1a.Imagine, you are an ISV, develop your product in ABAP and want to enable your customers to enhance your product at certain points. In this case, you provide enhancement options where you think they are useful.

1b. The same applies to the IT department of a multinational company. It develops some solution in ABAP and wants to make room for changes or enhancements that the different local subsidiaries can implement. Again using enhancement options are the suitable way to do this. Both cases are semantically and technically pretty the same, so that I decided to subsume them under the same use case.

2. The second use case is a bit more complex to describe: You are a SAP customer and need some enhancement of a SAP solution. Let us assume that the implicit enhancement options available in the relevant development objects do not suffice to accomplish this and that there are also no suitable explicit enhancement options. So you are left with the possibility to modify the relevant SAP development objects. But still there is room for using enhancement options. To reduce the effort necessary for adapting your modifications after an upgrade it is a good strategy to keep your modifications small. To minimize the size of your modification you create enhancement options within the modifications you insert. Then you add all further code to the implementation of these enhancement options. This way the modifications only contain these enhancement options and all the other additions are part of your namespace. In this use case modifications and enhancement cooperate in an interesting way.

The Limits of the Enhancement Framework


The very existence of this use case also helps to provide an answer to a question frequently asked: Namely, whether the new enhancement framework suffices to avoid all modifications. A realistic answer is: A clever use of enhancements enables you to do without modifications in many cases. On the one hand, there are explicit enhancement options provided by the developers of the respective solution. On the other hand, there are a huge number of implicit enhancement options. There are implicit enhancement points at the end of a function module, of a structure definition, of a report and of an include, in each defining section of a local class, and at the end of the implementation of a local class. Moreover, you can enhance a function module by additional parameter. A global class also offers a variety of implicit enhancement options: You can add methods, attributes, and interfaces to the class. Each method can be enhanced by a pre-exit, a post-exit and an overwrite-exit that substitutes the original implementation of the method.

Looking at the huge number of different implicit enhancement options it is probably possible to achieve your aim without modification very often. But still this is not always possible. Let us put it this way: What the new enhancement framework offers is intended to support modification-free enhancements to as large an extent as possible. But still, there is no guarantee that this is always possible. In case the enhancement options available for you do not suffice you should decide to create an enhancement option as a modification.

When to Use Source Code Enhancements


So much for the question when to create an enhancement option and the little excursus on the limits of the enhancement technology. The next question is what enhancement option you should prefer. In general, SAP recommends using a BAdI whenever it is possible. This is due to the reasons already named: A BAdI has a well defined interface and because of that the enhancement option provider has a firm control of the implementation. Moreover, the implementations can only access the data passed to them by the parameters of the respective methods. And again, it is you the BAdI provider, who determines which data should be passed to a BAdI method.

This great advantage of the BAdI is also a drawback in some situations. Thinking about this leads the way to understanding under which conditions a BAdI is not the suitable solution if you want to provide an enhancement option. This is, for example, a situation, in which you do not know which data the potential implementer of your enhancement options needs or provides. To put this point another way, if you do not know the interface, you cannot and, of course, should not use a BAdI. Given this condition, you should use the technology of enhancing the source code.

This enhancement technology comes in two flavors:

- At Enhancement points an implementer can add some lines of code which are executed at runtime when the line with the statement ENHANCEMENT POINT is reached. Then the control flows proceeds to the next line after the enhancement point. There can be none, one or many active source code plug-ins (as these enhancement implementation elements are called) assigned to an enhancement point. All these source code plug-ins are executed in addition to the code that is enhanced.

- An enhancement point cannot be part of another statement. This means a statement cannot be enhanced. And that fact sets a limit to the power of enhancement points. For example, there is no way to add a new condition to the where clause of a select statement by using an enhancement point. This is one prominent use case for an enhancement section. Imagine you have a select statement:

SELECT a b c FROM my_table INTO wa.

and want to leave it to the implementer to add a where-clause or select other fields from this table. So you mark the select-statement as an enhancement section, which looks like this:



Don't worry here about the details of the syntax. At this stage, you should just note that the code marked as an enhancement section is substituted by a source code plug-in as soon as one is provided. Obviously it is required by the logic of enhancement sections that one enhancement section can have exactly one active implementation.

Let me just restate the main point about the use of source code enhancements: This enhancement technology is suitable if you want to provide an enhancement option and cannot or do not want to specify an interface.

Defining an Enhancement Point


Now that you know why and when to use source code enhancements you are probably eager to know just how you create an enhancement point and how you implement it. Before going into any details let me just remind you of the basic structure of the enhancement framework that applies to source code enhancements as well: When you define an enhancement point, this point has to be part of an enhancement spot. This means if you cannot use an existing enhancement spot you have to create one when creating an enhancement point. The same applies in an analogous way to source-code plug-ins: A source code plug-in is uniquely assigned to an (simple) enhancement implementation. But this structure should be pretty familiar to anybody who has read the weblog in which I show how to implement a BAdI. (Simple) enhancement implementations serve as container for enhancement implementation elements.

So enough with the background structure. Let us go into the details and create an enhancement point. We go to the source code that we want to enhance, open the respective unit in change mode, put the cursor on a line and choose the right mouse menu:

image

In the next dialogue window we enter the name of the enhancement point and the name of the spot plus the name of the relevant package as shown below.

image

As a result an enhancement point is inserted into the code before the line where the cursor was:

image

This is what an enhancement point looks like. An enhancement point has a name that is unique within the source code unit it belongs to and is uniquely assigned to an enhancement spot.

Implementing an Enhancement Point


Now we switch our role. For the sake of simplicity we provide here both the definition and the implementation of our enhancement point. Of course, you know by now that the provider of an enhancement option and the implementer are two different roles. To implement an existing enhancement point is not possible in the change mode for an obvious reason. Of course not. The one who implements an enhancement option does not want do modify the program. That is what the whole business of the enhancement framework is about. So we switch to the enhancement mode by selecting the relevant button:

image

There we are. We choose the right mouse menu on the line where the enhancement point is and select Create in the submenu:

image

We get to this dialog window:

image

As I have told you have first to provide a container for the source plug-in, that is an enhancement implementation. Let us call our enhancement implementation ei_my_implementation. Of course you should not forget the explanatory text. It is possible to create a composite enhancement implementation by using the Create icon. But it is not necessary, and so we do without this meta-container here. And there we are:

image

Before inserting some code just note that the source code plug-in itself is not named. It is by assigning an enhancement implementation to an enhancement point that a source code plug-in comes into being. We just enter the code: WRITE 'implementation'.

After the code for the source code plug-in is supplied we should activate it by selecting the respective button:

image

Source Code Enhancements - The Structure of the Entities


For those who do not feel totally familiar with the structure of the entities, we have created so far let me just sketch the structure of entities we are concerned with:

image

Our enhancement point uniquely belongs to the (simple) enhancement spot es_my_spot. This spot is assigned to the (simple) enhancement implementation ei_my_implementation. (Simple) enhancement spots containing points or sections and the relevant (simple) enhancement implementations are in an n to m relationship. That means: Points belonging to one spot can be implemented by source code plug-ins belonging to different (simple) enhancement implementations. And source code plug-ins belonging to one (simple) enhancement implementation can implement points belonging to different (simple) enhancement spot. (This does of course not mean that one source code plug-in can implement different points) It is the compilation unit that holds the respective (simple) enhancement spots and (simple) enhancement implementations together: Spots containing points in one report cannot contain points in other programming units. The same is true for the enhancement implementations in an analogous way. An enhancement implementation cannot be assigned to points that belong to different programming units.

Source code plug-ins are unnamed. You create a source code plug-in by assigning a (simple) enhancement implementation to an enhancement point. In turn, this means that a (simple) enhancement implementation can only be assigned once to an enhancement point. Otherwise the identity of a source-code plug-in would be blurred. So much for the details of the structure of the entities involved when creating and implementing an enhancement point. By the way, the structure of the entities and the whole process of defining and implementing is pretty the same for an enhancement section. There is one notable difference: When implementing an enhancement section you have to make sure that there is not more than one active source code plug-in.

Replacing Source Code Plug-Ins


Now let us consider in brief how to handle a use case that is a bit more complex. Suppose you are a customer and want to change a source code plug-in created by a SAP industry solution. The background is that this code is specific to the industry solution and does not fit your needs totally though your company belongs to the respective industry. Changing the source code plug-in in the SAP namespace would, of course, mean modifying it. And this is no attractive move and should be avoided as much as possible. There is a better solution for this problem than modifying the source code plug-in in the SAP namespace.

The Enhancement Framework provides a nice feature to handle this situation. It enables you to overwrite an existing source code plug-in by using or creating a (simple) enhancement implementation that is an object of yours. This means you can substitute a source code plug-in without modifying the plug-in or the code unit it is plugged in. And this is how it works:

Position the cursor on the enhancement you want to replace, choose the right mouse button and select: Enhancement Implementation->Replace.

In the next dialogue window we have to enter the name of a new (simple) enhancement implementation. For reasons already given, it has to be a new one and has to be different from the enhancement implementation to which the source code plug-in to be substituted belongs:

image

What we do now is pretty the same procedure as when we originally implemented our enhancement point. We enter some code and activate it by selecting the button Activate Enhancements. This is what our enhancement point looks like now:

image

By using the respective entries in the context menu you can also change and delete source code plug-ins. But you should keep in mind: You should not touch source code plug-ins created by SAP as this would mean to modify a SAP object, in this case, the respective (simple) enhancement implementation. If a source code plug-in created by SAP does not meet your requirements, you should replace it in the way just shown in the last use case. So you should change and delete only the source code plug-ins you have created yourself. Instead of deleting an source code plug-in created by SAP you should replace it by an empty source code plug-in. Again, this is the way to avoid a modification.

Summary


By now you should have learned a lot of different things about the source code enhancement technology. Let us first consider the definition part or the role of the enhancement option provider. You know the use cases for this enhancement technology: As an option provider source code enhancements are the means of choice if you do not know the interface of the enhancements to be made. You can also create an enhancement point as a modification and add the rest of the code you need to a source code plug-in assigned to this enhancement point. This helps keeping unavoidable modifications small. Apart from these use cases, the enhancement technology recommended by SAP, in general, is to define a BAdI.

As to the implementing part, you know:

  • how to implement an enhancement point,

  • how to change or delete an source code plug-in of your own,

  • how to replace an existing source code plug-in in the SAP namespace.

How to implement a BAdI And How to Use a Filter - Part 4 of the Serieson the New Enhancement Framework



In the last weblog we defined a BAdI, provided a fallback class, instantiated the BAdI and called a BAdI method. Of course, we also provided an enhancement spot, because our BAdI, as every BAdI, needs a container to live in.

As you have learned, the fallback class is chosen in case no BAdI implementation is available. As we have not created a BAdI implementation so far, the method implementation of the fallback class was used in our example code. To change this, we create a BAdI implementation in this weblog. As soon as there is a suitable BAdI implementation the methods of the fallback class are not used any longer.

First let us have a short look at the entities we have so far: There is the enhancement spot z_es_calc_tax in which the BAdI z_badi_calc_vat lives. The BAdI interface defines an important part of the BAdI identity, insofar it defines the BAdI methods that can be used. Our interface z_if_calc_vat has one method get_vat( ).

image

The definition and the implementation of BAdIs are similar in one respect: Just as you need a container that is an enhancement spot for a BAdI, you cannot build a BAdI implementation unless you have the relevant container first. The relevant container type for BAdI implementations is called (simple) enhancement implementation. A simple enhancement implementation can keep many different BAdI implementations, but with one restriction:

A simple enhancement implementation is uniquely assigned to an enhancement spot. That means: A (simple) enhancement implementation can keep only BAdI implementations of BAdIs that belong to the spot the simple enhancement implementation is assigned to. This has the consequence: An (simple) enhancement implementation cannot keep BAdI implementations that implement BAdIs belonging to different spots.

This being so, we have first to create a container that is uniquely assigned to the enhancement spot our BAdI belongs to. Despite the fact that we have to do something pretty complex, the respective tool in the SE80 has paved a smooth way to do this. All you have to do is to press one button. This button is marked with an orange frame in the screenshot below:

image

We get to the dialog window, where we can create a (simple) enhancement implementation:

image

The next dialog window opens:

image

What are we asked to type in here? We have created so far a container for BAdI implementations, that is a (simple) enhancement implementation. This container is uniquely assigned to our enhancement spot. Once this connection is established, we can create a BAdI implementation for the BAdI within the enhancement spot. As we have defined only one BAdI within the enhancement spot, we have no choice. If we had more BAdIs in our enhancement spot, this would be the point where to select which BAdI we want to implement. As matters stand, we type in z_bdi_calc_vat_us as the name of the BAdI implementation, confirm and save the enhancement spot in the next window. There we are: This is (simple) enhancement implementation that contains the BAdI implementation z_bdi_calc_vat_us:

image

Obviously, the appearance of a (simple) enhancement implementation in the tool is pretty much like the one of an enhancement spot: Under the tab Enh. Implementation Elements there is a tree with the BAdI implementation(s) contained on the right-hand side. On the left, you see the properties of the marked BAdI implementation.

Note: Select the property "Implementation is active" under the header "runtime behavior". If you do this the text below changes to: "Implementation is called". That is intended to help you understand what the selection you have just made is for. Farther below, there is a list that shows the properties of the BAdI definition our BAdI implementation is assigned to.

To better understand the structure in which our objects are imbedded, let us have a look at this sketch:

image

At the top, there is the definition part: In principle, such a spot can contain many different BAdI definitions. Our enhancement spot contains only one BAdI definition. We have created a container for the BAdI implementations. This (simple) enhancement implementation is uniquely assigned to the enhancement spot, but one enhancement spot can have many enhancement implementations assigned to it. We have a one-to-many relationship between the enhancement spot and the enhancement implementation. With this relationship established, we have assigned a BAdI implementation to our BAdI. Again, this is a one-to-many relationship: A BAdI definition can have many BAdI implementations, but a BAdI implementation uniquely belongs to a BAdI.

Only if the relationship between the containers that is the enhancement spot and the enhancement implementation is established, you can assign a BAdI implementation to a BAdI definition. I have tried to show this in the picture by the large orange pipe that contains the small grey pipe.

You should keep in mind: When implementing a BAdI, you have first to establish a connection between the relevant containers. Based on this connection you can go on and implement the BAdI. This principle applies to source code plug-ins in an analogous fashion.

Now that we have a BAdI implementation, we need an implementing class. We click the triangle in front of the name of the BAdI implementation in the tree and next double-click Implementing Class:

image

It works the same way as with the creation of the fallback class in the last weblog. As we do not want to reuse an existing class we enter the name z_cl_calc_vat_us and select the Change icon. Again, we get to the Class Builder where the relevant interface methods are already defined. In our case it is only the method: get_vat( ).

We implement it:



We save and activate the class. If we have not activated the (simple) enhancement implementation before, we have to activate it now. Now, we return to the program:



We run the program, and what do we get? The result is a percentage of four percent. And this is because the fallback class is not selected, if we have an active BAdI implementation.

As a next step, we create another BAdI implementation, this time with the VAT rate of Great Britain. To make our example more like real world programming, we create another (simple) enhancement implementation, that is another container. This is because implementing the taxes for different countries most probably belongs to different projects and because the structure of the (simple) enhancement implementations should mirror the project structure.

We navigate to our enhancement spot and use the same button as we have done above. We name the simple enhancement implementation z_ei_bad_calc_gb, the BAdI implementation z_bdi_calc_vat_gb, and the implementing class Z_BDI_CALC_VAT_GB. The implementation of the method get_vat is the same as for the USA except for the VAT rate, which is 16,5% now. After saving and activating the enhancement implementation and the class we return to the program and run it again.

This time we get a short dump with the exception cx_badi_multiply_implemented. Remember: We have defined our BAdI as single use by deselecting the property "Multiple Use". When instantiating a single use BAdI you have to make sure that there exists only one active non-default implementation. Otherwise you get the respective exceptions at runtime. These exceptions can be caught, but this is not our strategy here. We want to avoid the exceptional situation right away.

Obviously, it would also make no sense, because we need exactly one result for our calculation and could not make any use of if the two BAdI implementations would be called one after another. This was just why we defined our BAdI as single use. What we need is a way to select among different BAdI implementations. And this is where the BAdI filter enters the game.

What we need is to change the BAdI definition, that is one we need to add a filter. You can define one or many filters for a BAdI. We will be modest and be content with one filter. Let us just define the filter in the BAdI definition, determine filter values for the respective BAdI implementation and use the filter in the instantiation of the BAdI handle. I hope in hindsight, you will understand what we have done and why.

You should keep in mind that what we do now when modifying our example does not take into account the differentiation between the BAdI provider and the implementer. In real life it is the BAdI provider who defines a BAdI with a filter or adds a filter to an existing BAdI. It is also part of this role to use the filter condition in order to select the respective BAdI implementation in the ABAP code. It is the implementer who determines the filter value(s) or an interval for one or many BAdI implementations. In the example we do all this ourselves for the sake of the example.

We start by adding a filter to our BAdI (role of BAdI provider) and to this we navigate to our enhancement spot and stay in the tab "Enh. Spot Element Definition" that shows a list of all the enhancement elements the spot. We switch to the change mode, mark our BAdI in the list, and click the Filter icon above. A dialog box opens and we fill out the relevant fields as shown below:

image

We confirm and get to the next screen. Obviously, the filter is now visible as a property below the BAdI. After activating the enhancement spot, we double click Implementation and navigate to the respective BAdI implementation by double-clicking the respective row in the table of BAdI implementations.

image

We switch to the change mode, click the triangle in front of the BAdI implementation in the tree and then double-click the filter icon below. In the next window we select the Combination icon, select "Country" as filter and confirm:

image

Double-clicking the row below "Combination 1" leads us to the next window:

image

As I have told you above, adding or changing a filter value of a BAdI implementation is part of the implementer's role.

After we have activated the (simple) enhancement implementation, we navigate back to the spot. Apparently, the other implementation, that is the one for USA needs also the respective filter value. So we go to the respective (simple) enhancement implementation and change the BAdI implementation in an analogous manner. The respective filter value for this country is 'US'. I skip the description of how to do this, because what we do is identical to what we have done before when creating the filter value for the BAdI implementation z_bdi_calc_vat_gb. We must take care that we do not forget to activate the (simple) enhancement implementations and to select the property "Implementation is active" for every BAdI implementation.

Now it is time to return to our program and adapt it to the modified BAdI (this is also the task of the BAdI provider). Running the syntax check shows you that you need to have a filter parameter in the GET BADI command if the BAdI you try to instantiate is defined with a filter. The requisite addition to the GET BADI command is FILTERS. It is after this keyword that you insert the name of the BAdI filter and a value the filter is compared to. Of course, we also have to take care that an appropriate value can be passed to the GET BADI routine:



If you pass "GB" to the parameter ctry, you will get a VAT rate of 16,5 percent. If the value of the parameter ctry is "US", the VAT rate will be 4 percent. When the parameter ctry has any other value, we will still get a calculated value for the data field 'percent'. And this is because we have defined a fallback class for our BAdI. The fallback class is not only selected if no BAdI implementation is available, but also if none of the existing BAdI implementations meets the filter conditions in the GET BADI command. Accordingly, we get a VAT rate of 20 percent. And this was the VAT rate we have implemented in the method get_vat in the fallback class.

And this is the end of this weblog. You have now learned how to create a BAdI implementation for a given BAdI. You know that a (simple) enhancement implementation is a container for BAdIs and moreover how and also why to assign it to a (simple) enhancement spot. That is you have understood the way the different elements of the enhancement framework interact when implementing a BAdI. And, in the second part; you have learned how to create a filter for a BAdI, how to determine filter values for BAdI implementations and what the appropriate syntax for calling a BAdI with a filter is like.