Aspect Oriented Programming
Scott Nykl
Software Engineering Department
University of Wisconsin-Platteville
Abstract
The Aspect Oriented Programming approach allows developers to add what are called aspects to an object oriented program [2]. These aspects enable one to add new functionality in a single location and simply specify that this new functionality is to be invoked when certain conditions arise. Thus, the ability to add functionality can now be achieved without wading through existing code and appending duplicate functionality across existing operations. This is especially useful for, high-level system-wide requirements, such as application logging or security requirements.
What Motivated Aspect Oriented Programming
Since thecreation of the first computer programs, the goal of succinctly creating reusable and maintainable systems of code has remained a never ending challenge. The beginning programs composed of cryptic binary strings were surpassed by more readable assembly languages. These, in turn, gave way to high-level programming languages. The first of these high-level programming languages was IBM’s Fortran, released in 1957 [1]. One of the most powerful features of high level languageswas the division created between a computer’s hardware and the coupling that hardware imposed upon the software. Additionally, another great stride wasthe advent of subprograms, or subroutines. These modular blocks of code allowed problems to be decomposed into smaller pieces increasing the reusability and maintainabilityof the code.
By the late 1960s, the inception of the Object Oriented Paradigm was realized. This technique allowed a collection of related data and a collection of related operations useful to that data to be encapsulated into objects [1]. The advantages of applying an object oriented approach to generate solutions for complex systems paved the way for modern C++ and Java [1].
However, the object oriented approach still had its share of problems. Although specific groups of data and operations werecohesively grouped together, othersecondary operations still needed to be duplicated across these objects. In other words,even though each object type had a specific purpose,general application-wide requirements still neededbe supportedvia these objects; i.e., logging application status to file may be required, but is not explicitly encapsulated in one single object type [2].
For example, imagine an employee record system which has a collection of employee related objects; each object has a cohesive set of operations that performnecessary manipulations on the data contained within that object. Now imagine that the system is extended to support loggingeach employee change to a logging database.
To implement this, developers will have to dive inside the employee objects and add additional operations to support logging; unfortunately, writing to a database, or ensuring sufficient privileges are obtained does not coherently fit with whatemployee objects represent. Additionally, wading through existing code and finding the exact locations to insertlogging operations can be a time-consuming, tedious, and error-prone process which can lead to software instability and securityflaws.
What Is Aspect Oriented Programming
A solution tothis problem can be solved byan Aspect Oriented approach. This approach allows developers toadd what are called aspects toan object oriented program [2]. These aspects enableone to add new functionality in a single location and simply specify that this new functionality is to be invoked when certain conditions arise. Thus, the ability to add functionality can now be achieved without wading through existing code and appending duplicate functionality across existing operations. In the case of our employee record system, we will be able to create one central collection of operations responsible for logging to a database, and then specify that a database write shall be invoked when an employee object is modified.
Today, the most commonly used multi-purpose aspect oriented programming language is AspectJ [2]. Simply stated, AspectJ is an aspect-oriented extension to the Java programming language [3]. To give a precise explanation of how this aspect-oriented extension functions, the following terms must be defined:
Table 1: Aspect Oriented Terminology
- Cross-cutting concern: Some aspects of implementation, such as logging, error handling, standards enforcement, and policy-layer modification are difficult to implement in a modular way. The result is that code is tangled across a system; this leads to quality, productivity, and maintenance issues. These issues are cross-cutting concerns [4].
- Advice: This is the additional code that one wants to apply to an existing model to add support for features such as logging, error handling, standards enforcement, and policy-layer modification [2].
- Point-cut: This is the term given to the point of execution in the application at which a cross-cutting concern needs to be applied. In our example, a point-cut is reached when a thread of execution within the employee record system enters a method responsible for modifying an employee; a second point-cut is reached when that thread of execution leaves the method responsible for modifying an employee [2].
- Aspect: The combination of the point-cut and the advice is termed an aspect. In our example, we add a logging aspect to our employee record system by defining a point-cut and giving the correct advice to execute when that point-cut is reached [2].
HowDoes Aspect Oriented Programming Work
Now, let us assume we are to implementthe logging extension for this employee record system; Figure 1below, defines a single aspect that handles logging updates whenever specific changes are made to employee objects.
1 aspect LoggingHandler
2 {
3 privatestatic boolean EmployeeChangeLoggingEnabled = true;
4 publicstaticvoid EnableEmployeeChangeLogging()
5 {
6 EmployeeChangeLoggingEnabled = true;
7 }
8 publicstaticvoid DisableEmployeeChangeLogging()
9 {
10 EmployeeChangeLoggingEnabled = false;
11 }
12
13 pointcut LogEmployeeChange(Employee e): target(e) &
14 ( call(public * setName(..)) ||
15 call(public * setAddress(..)) ||
16 call(public * setSalary(..)) ||
17 call(public * setOfficeAddress(..)) );
18
19 before(Employee e): LogEmployeeChange(e)
20 {
21 if( EmployeeChangeLoggingEnabled )
22 {
23 /*Connect To Logging Database */
24 WriteToDatabase( "Modifying Employee From: " );
25 WriteToDatabase( e.ToString() );
26 }
27 }
28
39 after(Employee e): LogEmployeeChange(e)
30 {
31 if( EmployeeChangeLoggingEnabled )
32 {
33 /*Connect To Logging Database */
34 WriteToDatabase( "Modifyed Employee To: " );
35 WriteToDatabase( e.ToString() );
36 }
37 }
38 }
Figure 1: LoggingHandler Aspect
Let us begin by stepping through the code in Figure 1. At first glance, the Object-Oriented programmer will immediately recognize a familiar structure. The entire aspect looks much like a class declaration with a few important changes.
Firstly, instead of the keyword “class”, AspectJ uses the keyword “aspect” to declare an Aspect. Another noticeable difference related to the “aspect” keyword is that all data and operations specific to the Aspectare declared as “static”; note that lines 13 through 37 represent special Aspect-Oriented structures and are not declared as “static”. These static data and operations are essential since the programmer never actually instantiates an Aspect; rather, the Aspect is a singleton, only one instance can exist within a program, and this is created automatically at run-time [5]. This also implies that there is only one single copy of the Aspect’s state variables; thus, for our example, there exists only one “LoggingHandler” Aspect and only one “EmployeeChangeLoggingEnabled” Boolean; these data remain resident until the program terminates[5].
Secondly, AspectJ uses a “pointcut” keyword to define a point-cut. The point-cut, as defined above, is a method ofencapsulating all cross-cutting concerns that match a specific set of specified criteria. For our example, the cross-cutting concerns are related to operations that directly modify an employee object; thus, our “pointcut” declaration specifically identifies employee operations which are used to directly modify employee objects. Let’s take a closer look at lines 13 through 17:
13 pointcut LogEmployeeChange(Employee e): target(e) &
14 ( call(public * setName(..)) ||
15 call(public * setAddress(..)) ||
16 call(public * setSalary(..)) ||
17 call(public * setOfficeAddress(..)) );
Figure 2: Pointcut Declaration
Here, we declare a point-cut named “LogEmployeeChange” and specify the specific points where an employee object is changed. We can see that the point-cut deals only with objects of type “Employee” (line 13), and only deals specifically with 4 types of methods contained within the “Employee” class (lines 14-17). Line 14 explicitly says, “for any ‘public’ method of class ‘Employee’ with any type of return parameter (‘*’), a name of ‘setName’, and a parameter set of anything (‘..’), execute the corresponding Advice [5]. Lines 15 through 17 are then chained to line 14 using the classic or operator “| |”; these lines specify the other prototypes of the employee class methods which are used to modify an employee object[5]. It is important to note that the use of wildcards allow the Aspect programmer to include a large grouping of functions in a single line.
Thirdly, now that the point-cut is specified, we must look at the corresponding Advice associated with these point-cuts; that is,the code that is executed once the point-cut is reached. As shown on lines 19 and 39 of Figure 1, the keywords “before” and “after” are used to declare Advice blocks. The “before” Advice block is executed prior to the corresponding method which triggered the point-cut. Conversely, the “after” Advice block is executed after execution returns from the corresponding method which triggered the point-cut[5].
So, for our employee record system, we can seein lines 19 through 27 the before Advice. Line 19 basically says, “Since my associated point-cut has been triggered, execute the code in my block before executing the method which triggered the point-cut.” Additionally, the actual instance of the Employee class which will be modified is passed into the before Adviceas “Employee e” [5]. Thus, lines 20 through 27describe how we create the first half of an entry to the logging database. First, we check to see if logging is enable, if it is enabled, we connect to the database, and record a .ToString() output of the Employee object. It is important to note that this specific output represents the state of the Employee objectbefore that Employee object is modified by the point-cut invoking method [5].
Thus, after executing the before Advice, the method which triggered the point-cut is executed; this method could be “setName”, “setAddress”, etcetera. Once execution returns from this method, the after Advice is considered. When the after Advice is executed, the newly modified instance of the Employee class is passed in as “Employee e” [5]. Thus, lines 30 through 37 describe how we create the second half of an entry to the logging database. First we check to see if logging is enabled, if it is enabled, we connect to the database, and record a .ToString() output of the Employee object. It is important to note that this specific output represents the state of the Employee object after that Employee object is modified by the point-cut invoking method.
So, we have now logged the before state and the after state of each modification of an employee object; our task of implementing the logging extension of the employee record system is complete. We did not have to wade through existing code and insert logging logic across multiple methods; we simply identified the methods responsible for directly modifying an Employee object, added them to a point-cut definition, and specified the associated advice.
The employee record system described within this text shows a simple implementation of Aspects, however, Aspects can grow more complex and can be used for more than just simple method calls. For example, point-cuts can catch method or constructor invocations, the handling of exceptions, field assignments, and accesses [5]. However, these more advanced operations are beyond the scope of this text.
Additionally, since AspectJ is an extension to Java, the syntax / semantics, bindings / type checking, data types / expressions / ADT, control structures, subprograms, Object-Oriented support, concurrency, and exception handling are identical to Java with the exception of the new Aspect related structures discussed previously.
Case Study of Aspect Oriented Programming
In this section, we will discuss cases in which the features of Aspect Oriented Programming are highly beneficial for designers, implementers, and maintainers.
Apache Tomcat
Tomcat is a free, open-source implementation of Java Servlet and JavaServer Pages developed under the Jakarta project at the Apache Software Foundation. This application was developed as an open source project and designed using object-oriented methodology.
Figure 3: Relevant XML Parsing code within Tomcat
As a result of this object-oriented approach, the majority of functionality is contained within well-decomposed, cohesive classes (see Figure 2 above and Figure 3 below); however, high-level system-wide requirements, such as application logging, are not represented by any abstract data type.
Figure 4: Relevant URL Pattern matching in Tomcat
Conversely, the logging subsystem is scattered across many different and unrelated modules (see Figure 4 below). Because of this, many maintenance issues arise. Firstly, a large amount of redundant logging code exists in many places. Secondly, no explicit logging structure exists within the design; that is, the big picture of this tangled code is not clear at the source-code level. Finally, this logging subsystem is very hard to modify or extend; one would have to find all the related code and ensure all of it was modified consistently. Attempting to overhaul the logging subsystem for Tomcat without Aspect Oriented Programming techniques would be a daunting task.
Figure 5: Relevant Logging code within Tomcat
Fortunately, the simple creation of a logging Aspect would allow a programmer to centralize the entire logging subsystem into a single module. Firstly, the redundant logging code scattered throughout the system could be removed from all other modules; this would reduce footprint size, ease readability, increase cohesion, and decrease coupling. Secondly, the centralized logging subsystem will be much more modifiable and seeing the big picture at the source-code level is much easier.
Conclusion
In conclusion, AspectJ and Aspect-Oriented Programming represent a way to cleanly modularize high-level requirements which span across the scope of many different classes and operations. Using AspectJ can greatly alleviate issues related to logging, monitoring, application-spanningrequirements, and many other issues that commonly cause headaches for even well-designed Object-Oriented systems [3].
References
1. Ricadela, Aaron. “Retooling The Programmers”. Information Week. November 18, 2002.
2. O’Regan, Graham. “Overview of Aspect Oriented Programming”. January 14, 2004. ONJava.com.
3.AspectJ Project Home.
4.AspectJ Development Tools.
5. The AspectJ Language – The Anatomy of an Aspect.