obile devices are becoming the most prevalent computing platform ever. With close to 2 billion mobile handsets in use everyday, mobile is not a platform that any developer can ignore. However, when developing mobile applications developers are finding it challenging to take full advantage of the true revenue potential of this rapidly growing market.
The process of mobile content deployment?which includes the development, adaptation, optimization, localization, testing/certification, channel packaging, and channel stocking of content for mobile devices?is very different than in the enterprise and desktop worlds. Mobile phones are personalized devices, which leads to significant variation between devices, with handset manufacturers offering different screen sizes, performance, memory, sound systems, form factors, keypad layouts etc. The result is fragmentation of the runtime environment. This is further complicated by operator specific APIs (e.g. Sprint’s Game Lobby), network-related issues (e.g. certain ports are blocked on some mobile networks), and other operator-specific requirements or channel packaging.
With more than 1,000 handset models already on the market and at least 20 new devices being introduced every month, the challenge is becoming increasingly complex. Further complicating the mobile deployment process are the unique content submission requirements of more than 700 mobile operators. All of which make it impossible to deploy the same mobile application on all devices, across all channels.
Fortunately, we do have technologies that can help ease the burden. In getting mobile content from the development stage to the end user, aspect-oriented programming (AOP) provides developers with a way to expedite and reduce the complexity of the entire process. Whether the target platform is MIDP, BREW, Windows Mobile, DoJa (DoCoMo Java), or WIPI (Wireless Internet Platform for Interoperability), AOP can enable you to modularize and reuse code snippets for device-/operator- specific issues or other optimizations without reverting to the lowest common denominator approach. AOP also provides scalability to efficiently add more people to the project to increase the throughput linearly.
AOP Background and Terms
Before examining AOP in the context of mobile content deployment, I’ll first review the fundamentals of AOP.
OOP is often not sufficient in modularizing code. While most classes in OOP perform a single, specific function, they often share common requirements with other classes. These requirements are known as cross-cutting concerns.
AOP enables developers to dynamically modify static OO models to meet new requirements; it facilitates modularization of cross-cutting concerns. This cross-cutting code module can be kept in a single location and needn’t be scattered across the existing model to the areas where it’s needed.
Logging is an excellent example of a cross-cutting concern. Every developer has used debug logs at some point in time, and logging most likely affects every single logged part of the software. As a result, logging code cross-cuts all logged classes, methods, and/or procedures.
Assume that you are developing a MIDP application that occasionally crashes when getting system events in your Canvas class (such as key presses) so you decide to add some logging code in all system event callbacks as follows:
void paint(Graphics g) { logging("entering paint"); // your paint code logging("leaving paint");}void keyPressed(int keyCode){ logging("entering keyPressed"); // your key processing code logging("leaving keyPressed");}void keyReleased(int keyCode){ logging("entering keyReleased"); // your key processing code logging("leaving keyReleased");}void keyRepeated(int keyCode){ logging("entering keyRepeated"); // your key processing code logging("leaving keyRepeated");}void hideNotify(){ logging("entering hideNotify"); // your hideNotify code logging("leaving hideNotify");}void showNotify(){ logging("entering showNotify"); // your showNotify code logging("leaving showNotify");}
Clearly, this can become a very tedious task. Every time you want to trace more method calls, you’d have to add the same logging code twice. By the time you had finished debugging, your code would be littered with logging methods that have to be removed manually. Performing a logging task (or any kind of cross-cutting task) in this manner decreases the program modularity and tangles the code. This is what OOP was not designed to address.
What you really want is a way to specify “add a logging method call to the beginning and the end of these six methods” in a separate module, which translates into the following pseudo code:
loggingAspect{ loggableCalls = paint, keyPressed, keyReleases, keyRepeated, showNotify, hideNotify; insertBefore: loggableCalls { logging("entering " + $methodName); } insertAfter: loggableCalls { logging("leaving " + $methodName); }}
As you can see, the logging code is now totally encapsulated in a reusable module with the core modules untouched. It makes the resulting code much cleaner.
The previous example only involves modifying one source file. If the logging code must span multiple files, using traditional methods will be even less desirable. Without AOP the logging code might need to be added to multiple locations of multiple source files (see Figure 1). Using AOP, the logging code can be modularized and “woven in” to the executable using a weaver (see Figure 2).
![]() | |
Figure 1. Without Aspects: Handling a cross-cutting concern such as logging, without aspects, requires multiple versions of the source. |
Clearly, using AOP means the traceability, reuse, and maintenance of the entire source code can be greatly improved. Before moving on, I’d like to introduce three AOP vocabulary words that will come in handy: pointcut, advice, and aspect.
Pointcut
A pointcut is the point (or points) of execution in the application at which cross-cutting concern needs to be applied. In the above example:
loggableCalls = paint, keyPressed;
Pointcuts can be a combination of method execution, instantiation of an object, initialization of a field, catching of an exception, or any other well-defined points along the execution of a program.
Advice
Advice is the code that you want to apply to your existing model. In the above example:
insertBefore: loggableCalls { logging("entering " + $methodName); } insertAfter: loggableCalls { logging("leaving " + $methodName); }
Aspect
The combination of pointcuts and advices form an aspect.
Using AOP to Help Mobile Development
Typically, when porting to multiple devices due to differences in performance, available heap memory, and screen sizes, you’re forced to modify the original source code. For example, to port a game application to a small screen device, one might need to use a smaller font in the main menu to avoid scrolling. One might also need to remove certain screen elements if the screen is too narrow. Depending on the screen size, you might have to do both. Similar requirements apply to changes of performance and heap memory optimization. The end result is a set of similar but unique source code for each device.
Using AOP, these changes and the conditions for these changes to be applied are stored in the specific aspects instead of being scattered randomly throughout the source code (see Figure 2).
![]() | |
Figure 2. Aspects: The diagram shows the abstraction that aspects are capable of. Here, three aspects are wrapped in a weaver and each device takes from it what it needs to run the application correctly. |
AOP provides many possibilities when it comes to application-specific optimization or meeting channel packaging needs. For example, channel-packaging APIs such as Sprint’s Game Lobby add another dimension to the complexity of mobile content deployment. Using AOP, a developer can create a generic, application-agnostic aspect that does all of the above without modifying the original code.
In the case of application-specific optimization, when porting to a larger screen device it is common that font size and spacing between strings must be changed to improve legibility. AOP enables developers to create a single aspect similar to the those in Figure 2 that encapsulates all the changes related to large-screen optimization—without touching the original source code.
Device Bugs
The Java ME Mobile Media API (MMAPI) is one of the most common developer kits for building easily portable mobile applications. But there are a few issues which MMAPI is simply ill-equipped to handle. For example, some devices can only play one sound at a time. To work around this issue in the MMAPI, one needs to call Player.stop() for the player in use before playing a new sound. In other words, the following changes are required:
- Add static javax.microedition.media.Player currentPlayer = null; to the MIDlet class
- In all occurrences of player.start(), change the code to the following:
if(MyMIDlet.currentPlayer != null) { currentPlayer.stop(); } player.start(); MyMIDlet.currentPlayer = player;
- In all occurrences of player.deallocate() and player.close(), insert the following code before the above:
if(MyMIDlet.currentPlayer == player) { currentPlayer = null; }
There are plenty of traditional techniques to resolve the problem above. Unfortunately, these are not without complications. For one, the code to fix this sound issue is scattered in at least three places. Worse, if done improperly, you’ll quickly find yourself in “pre-processor hell” where, before every occurrence of player.start(), you must insert:
//#if (manufacturer=="NOKIA" AND model=="4321")//OR (manufacturer=="NOKIA" AND model=="5432")//OR (manufacturer=="MOTOROLA" AND model=="V432")//OR (manufacturer=="MOTOROLA" AND model=="V321")//OR (manufacturer=="SONYERICSSON" AND model=="W100")//OR (manufacturer=="SONYERICSSON" AND model=="W200")//OR (manufacturer=="SAMSUNG" AND model=="X123")//OR (manufacturer=="SAMSUNG" AND model=="X456") if(MyMIDlet.currentPlayer != null) { MyMIDlet.currentPlayer.stop(); } MyMIDlet.currentPlayer = player;//#endif
every occurrence of player.close() and player.deallocate() with:
//#if (manufacturer=="NOKIA" AND model=="4321")//OR (manufacturer=="NOKIA" AND model=="5432")//OR (manufacturer=="MOTOROLA" AND model=="V432")//OR (manufacturer=="MOTOROLA" AND model=="V321")//OR (manufacturer=="SONYERICSSON" AND model=="W100")//OR (manufacturer=="SONYERICSSON" AND model=="W200")//OR (manufacturer=="SAMSUNG" AND model=="X123")//OR (manufacturer=="SAMSUNG" AND model=="X456") if(MyMIDlet.currentPlayer == player) { MyMIDlet.currentPlayer = null; } MyMIDlet.currentPlayer = player;//#endif
Plus, you must add the following to the MyMIDlet class:
static javax.microedition.media.Player currentPlayer = null;
Needless to say, the changes are very scattered and unreadable.
By using AOP you can consolidate all the changes into a single aspect. The following pseudo-code best illustrates how it works:
ensureSingleActivePlayerAspect { pointcut1 = class: MyMIDlet; addField : pointcut1 { static javax.microedition.media.Player currentPlayer = null; } pointcut2 = methodCall: Player.start(); insertBefore : pointcut2 { if(MyMIDlet.currentPlayer != null) { MyMIDlet.currentPlayer.stop(); } MyMIDlet.currentPlayer = player; } pointcut3 = methodCall: Player.close(), Player.deallocate(); insertBefore : pointcut3 { if(MyMIDlet.currentPlayer == player) { MyMIDlet.currentPlayer = null; } } }
The beauty of this approach is that all the code related to this particular sound issue is now nicely contained in one module without contaminating the original source code. And the pointcuts clearly specify where this code should apply to the original source code. The maintainability and readability are greatly improved.
It should be noted that it is possible to implement AOP-like behavior with pre-processors by using #define statements to replace Player.start(), Player.close(), and Player.deallocate(). That said, it is more desirable to use a language or a system that has native support for AOP. It is analogous to the use of procedural language to implement OOP. When C++ became a mainstream programming language, there were certain implementations of OOP that favor C instead. Over time, these C based implementations disappeared as more and more developers adopted languages with native OOP support.
Once mobile content is developed, AOP can provide developers or publishers with a powerful tool to eliminate complexity and successfully deploy content. Using AOP can accelerate time to market by addressing cost-cutting concerns, modularizing concerns into aspects, and reusing aspects for more than one device. The result is a more efficient mobile deployment process where it is easier to ensure projects stay on time and within budget.