Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Aspect- vs. Object-Oriented Programming: Which Technique, When? : Page 3

Aspect-oriented programming claims to address problems that traditional object-oriented programming doesn't completely or directly solve. Find out how true that claim is with a line-by-line comparison of the two techniques.


advertisement

AOP Approach

The sequence diagram in Figure 3 illustrates the design of the AOP approach and the interaction between the classes at a higher level. You might want to compare it with Figure 1 to understand the concept better.

 
Figure 3. The Design of the AOP Approach

The objective of the application is to fill the map in the BusinessUnitService class with BusinessUnit instances by reading the records from the CSV file. Using AOP to populate this map is like a backdoor approach, where the control is delegated to a repository class for reading BusinessUnit records from storage.



AOP is all about defining point cuts and advices. A point cut is a place of execution in the source code. The above example defined a point cut for the method findBusinessUnits in the class BusinessUnitService. An advice is a piece of code that executes when a point cut is reached. The BusinessUnitPersistentAspect class contains the advice method findAllBusinessUnits, which loads data from storage and uses the factory class to create the BusinessUnit object. This object is then added to the map. The map reference is retrieved from the BusinessUnitService instance. The point cuts and advices form an Aspect.

The OOP approach delegates the call to a DAO class in order to read from storage. With AOP, you define a point cut in the domain class and define an advice for reading from storage. The AOP framework would inject the code written as an advice, either at the time of execution (online weaving) or during compilation (offline weaving).

To summarize, when the call to findAllBusinessUnits in the BusinessUnitService class is made, the AOP framework injects code that is the advice method and pre-populates the map instance with the BusinessUnit instances by reading values from storage. This way, the persistence aspect of the application can be moved out of the domain model.

The Aspects in the New Approach

This section discusses how each of the aspects in the application modeled using OOP can be done using the AOP approach.

Resources for an Operation

A buffered reader resource is set to the persistence methods in the BusinessUnitPersistenceAspect class. You can define aspects even for aspects, but to keep things simple, this discussion concentrates on only the find methods in the class. Focus on the highlighted lines of the following code:

@Aspect("perJVM") public class BufferedFileReaderAspect { @Expression("execution(* org.javatechnocrats.aop.withaop.aspects.BusinessUnitPersistenceAspect.find*(..))") Pointcut businessUnitPersistenceAspect; // Other point cut definitions @Expression("businessUnitPersistenceAspect || employeePersistenceAspect || managerPersistenceAspect") Pointcut allPersistencePointcuts; private Map<Class, String> fileNames; public BufferedFileReaderAspect() { System.out.println("BufferedFileReaderAspect created"); fileNames = new HashMap<Class, String>(); fillFileNames(); } @Before("allPersistencePointcuts") public void assignReader(JoinPoint joinPoint) throws Throwable { System.out.println("assignReader advice called"); Object callee = joinPoint.getCallee(); IBufferedFileReaderConsumable bufReaderConsumable = (IBufferedFileReaderConsumable)callee; Class persistenceClass = callee.getClass(); String fileName = fileNames.get(persistenceClass); FileReader fileReader = new FileReader(fileName); BufferedReader bufferedReader = new BufferedReader(fileReader); bufReaderConsumable.setBufferedReader(bufferedReader); } @AfterFinally("allPersistencePointcuts") public void releaseReader(JoinPoint joinPoint) throws Throwable { // We would release the buffered reader resource } // Other methods }

The code tries to create a point cut for all the method names, starting with find in the BusinessUnitPersistenceAspect class. Whenever these methods are called, the aspect class method assignReader is called before the find method executes. Here, it retrieves the callee class instance and sets the newly created buffered reader.

Similarly, in the releaseReader method, the code closes the buffered reader set previously. This section explains only the @before and @AfterFinally point cuts, which are defined using annotations in J2SE 5.0. Alternatively, you can declare them in the aspect definition XML file. You can examine the aop.xml file in the etc folder in the example code. (To get to know various types of point cuts, refer to the links in the Related Resources section in the left-hand column.)

Persistence

As previously discussed, the OOP approach for application persistence fills the Map with BusinessUnit instances. In the highlighted code below, the defined advice method findAllBusinessUnits would be invoked when the findAllBusinessUnits method in the BusinessUnitService class is called:

@Aspect("perJVM") public class BusinessUnitPersistenceAspect implements IBufferedFileReaderConsumable { private BufferedReader buffFileReader; @Before("execution(Collection org.javatechnocrats.aop.withaop.BusinessUnitService.findAllBusinessUnits())") public void findAllBusinessUnits(JoinPoint joinPoint) throws Throwable { System.out.println("findAllBusinessUnits advice called"); Map<String, BusinessUnit> businessUnits = ((BusinessUnitService)joinPoint.getThis()).getBusinessUnits(); String businessUnitRecord; while((businessUnitRecord = buffFileReader.readLine()) != null) { BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord); businessUnits.put(businessUnit.getId(), businessUnit); } } public void setBufferedReader(BufferedReader buffFileReader) { System.out.println("BusinessUnitPersistenceAspect.setBufferedReader called"); this.buffFileReader = buffFileReader; } public BufferedReader getBufferedReader() { System.out.println("BusinessUnitPersistenceAspect.getBufferedReader called"); return this.buffFileReader; } }

The advice method reads the records from storage and uses the factory class to create BusinessUnit class instances. The created instances are then added to the Map, which handles the persistence aspect of the application.

Logging

The example in this article doesn't contain the complete AOP solution for logging. However, it has defined a point cut for the java.lang.Object class's toString method in order to get the debug information about domain class objects. Hence, the domain classes don't need to implement the toString method to form a debug string using a StringBuffer, which you normally do for all the classes in an application:

@Aspect("perJVM") public class LoggingAspect { @Around("execution(String org.javatechnocrats.aop.withaop..*.toString())") public Object toStringAdvice(JoinPoint joinPoint) throws Throwable { System.out.println("toStringAdvice called"); String toString = (String)joinPoint.proceed(); Object target = joinPoint.getThis(); Field fields[] = target.getClass().getDeclaredFields(); List members = new ArrayList(fields.length + 1); members.add(toString); for(Field field : fields) { field.setAccessible(true); Object member = field.get(target); members.add(field.getName() + "=" + member); } return members.toString(); }

You can use this sample code to complete the error handling aspect as well.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap