Mapping Well-Known Patterns onto Symbian OS : Adapter

2/4/2012 4:13:04 PM
1. Problem
1.1. Context

There is a pre-existing component, the adaptee, which exposes an interface that you wish to use via an alternative incompatible interface, the target.

1.2. Summary

You need to resolve one or more of the following:

  • You wish to reduce your development costs by porting a pre-existing component, the adaptee, to a new environment.

  • You have re-engineered a component, the adaptee, but you wish to support the old interface, the target, to preserve compatibility for legacy clients.

  • You wish to increase the functionality and flexibility of a component by re-using existing components, the adaptees, at run time.

1.3. Description

This pattern was originally described in [Gamma et al., 1994]. Hence in this discussion rather than examine the pattern itself in too much detail, we place emphasis on how it can be used on Symbian OS, covering a range of diverse circumstances.

The context of this pattern of having to match incompatible interfaces can arise in numerous different situations. Software based on Symbian OS is subject to many pressures all of which can give rise to problems of mismatching interfaces: it is an evolving system with a large user base, which means that maintaining interface compatibility from release to release is important not just for the operating system itself but also for any services and frameworks built on top of it. It targets a domain which covers a wide and diverse set of technologies, many of which are standards-driven and must interoperate, and it is a specialized operating system, carefully evolved to work in a demanding environment.

In addition, you may not be able to change existing components to make compatible what were incompatible interfaces. The reasons for this range from pragmatic ones of engineering cost or risk, to business reasons (for example, licensing terms), to quality reasons (avoiding tight coupling between logically independent components).

Each of the following kinds of problem demonstrates the same common factor: the need, for whatever reason, to make incompatible interfaces work together, without changing existing components:

  • Preserving compatibility

    When the legacy functionality provided by one component is made obsolete by changes that, as your system evolves, introduce new, alternative functionality which meet at least the same requirements, clients relying on the legacy behavior must still be supported, if only for a transitional period. For reasons of maintainability and code size, it may not be feasible to leave the old component in place alongside the newer version.

  • Wrapping components to ease porting

    For existing components created for a different environment from the one you would like to use it in, it may be impossible or undesirable to make changes to the component. This commonly arises when integrating an industry-standard implementation of a specific technology.

    The interfaces presented to a component in the Symbian OS environment may be incompatible with what the component expects and, vice versa, the interfaces it presents may be incompatible with what potential Symbian OS clients of the component expect.

    For Symbian OS, the problem is complicated by the fact that native C++ interfaces are often not directly usable by ported components written in standard C or C++; and standard C or C++ client interfaces of ported components are typically not directly usable by native Symbian OS clients.

  • Run-time adaptation

    Different components that all store state may present very different settings interfaces, but updating their settings may be the responsibility of a single agent or service. Hardwiring knowledge of each different settings interface into the updating service may be a poor design choice, because it breaks modularity and flexibility by forcing a tight coupling between many different components, possibly in quite different parts of the system.

1.4. Example

Here we give an example for each of the three main uses of this pattern identified in the Description above.

Preserving Compatibility

Symbian OS provides a communications database which is a persistent store of the data required to configure communications components or to make connections with remote servers. Until Symbian OS v9.1, the interface to this communications database was via the CCommsDatabase provided by the CommDB component that used the existing OS database service DBMS.

However, in Symbian OS v9.1, Symbian introduced a new component called CommsDat that provides the same interface as the old CommDB, CCommsDatabase, but uses the Symbian OS Central Repository instead. This move makes use of the extra functionality provided by the Central Repository compared to DBMS, such as standard tools to set up and configure the Central Repository during development as well as performance enhancements such as caching repositories used by multiple clients.

Since the underlying data is stored in a different place, the old CommDB component cannot simply be maintained alongside the new CommsDat component. Hence an alternative solution is needed which maintains compatibility to allow the legacy clients of CommDB to continue to work but which uses the new storage location.

Wrapping Components to Ease Porting

Before Symbian OS v9.2, a native database component known as DBMS provided all clients with a database service supporting the SQL specification. However, for v9.2, Symbian decided to port the open source SQLite component[] to Symbian OS. One of the main reasons for this was that there was a requirement to provide more SQL features, such as triggers, that aren't provided by DBMS.


One decision taken early on was not to attempt to attempt to preserve compatibility with the old DBMS interface but instead to provide an interface to SQLite alongside it. This was because, whilst SQLite provided more SQL functionality than DBMS, it didn't, at the time, provide a superset, i.e. there is some SQL functionality that DBMS supported that SQLite didn't.

This left the following remaining challenges to be overcome to integrate SQLite into Symbian OS:

  • SQLite exposes a C-based API to clients but most Symbian OS programmers would expect a Symbian OS C++ API.

  • The databases accessed through SQLite need to comply with features of the operating system such as platform security as well as backup and restore.

  • SQLite expects a POSIX API to support it from underneath.

Run-time Adaptation

Consider the example of the remote management of a device, for example, a network operator configuring an email account on a subscriber's device 'over the air'. In this case, the provisioning agent or service needs to provide a service to the network that is logically identical to a service provided locally on the device. However, it's often the case that the standards-driven network interface is different to the interface provided locally. Hence a means is needed to join the two interfaces together.

That's not the end of the problem though because clearly it would be beneficial to deploy the same device management system on as many devices as possible and they will vary in their support for features such as email. This means that the central device management system needs to provide an extension point which discovers and loads plug-ins representing the components being remotely managed. This extension point defines a target interface into which we need to adapt existing components.

2. Solution

This pattern decouples interfaces by creating an intermediary class, called the adapter, whose purpose is to adapt the interface presented by one class, the adapter, and present the interface, known as the target, expected by another class, the client, that wants to use the adapter. This pattern can therefore be used to solve the problem of incompatibility between two existing interfaces, without requiring changes to either interface.

2.1. Structure

From the client's point of view, only the adapter need be visible or known; the implementation of the adapter and any details of the conversion or translation it performs using the adaptee can remain hidden from the client. In short, the client never doesn't directly depend on the adaptee. This is achieved by the structure shown in Figure 1.

2.2. Dynamics

At its simplest, an adapter is a wrapper. For example, methods are provided that convert the API of a ported application and make it appear to be a native API to clients. Wrappers can also be used to convert outbound system calls from the ported component to match native Symbian OS calls. The adapter simply redirects a call made through the target's interface to a matching adaptee function (see Figure 2).

In more complex cases, rather than simply wrapping each method, an adapter may be a complete component that intercepts and converts calls made to one API into calls to a quite different API where there doesn't exist a close match for the target method called. The adapter may even need to use multiple adaptees to satisfy the client's request on the target interface (see Figure 3).

Figure 1. Structure of the Adapter pattern

Figure 2. Dynamics of the Adapter pattern (simple)

In the most complex case, at run time the adapter may need to select and load the adaptee that satisfies the client's request on the target interface. In these more complex cases, it is common to implement the adapter in its own DLL separately from the adaptees so that clients have even fewer dependencies on the adaptees. This allows the adapter to use the ECom service to dynamically load adapters as plug-ins at run time if needed.

Figure 3. Structure of the Adapter pattern (complex)

2.3. Implementation

There's little to say about the implementation of this pattern over and above what's already been said in the Structure and Dynamics sections. The one exception to this is if you wish to load adaptees at run time. If so, you should consider using Buckle (see page 252) to do this securely based upon the ECom plug-in service provided by Symbian OS.

2.4. Consequences


  • This pattern is simple to implement and understand.

  • Development time is reduced by enabling the re-use of existing components.

  • By preserving any pre-existing interfaces, you reduce your testing costs because any existing tests written to use the target interface also work for the adaptees if the tests use the adapter.

  • It preserves decoupling between the target and adaptee interfaces. By keeping interfaces decoupled, your solution remains flexible which makes future maintenance and evolution easier. Typically, it is much easier to update the adapter in the case of future changes than to try to evolve the clients or the adaptee if that would even be possible.

  • In the case of a run-time adapter design, new adaptees can be integrated with potentially no change to the client or even the adapter. This makes your design more open and easily extensible.


  • It imposes additional overheads on the use of an adaptee interface because an additional layer is interposed between the client and the functionality it wants to use in the adaptee. This increases both the code size and the execution time for the solution although they are unlikely to be significant in all but the most extreme of cases.

  • If you are using this pattern to preserve compatibility by maintaining a legacy API in addition to a new API then this necessarily increases the complexity of the system since there are now two APIs for clients to choose from during development as well as two APIs for the provider of the adapter to support.

  • Using a run-time adapter based on the ECom plug-in service has no impact on execution time once the plug-in has been loaded. However, searching for and loading a plug-in is an additional overhead compared to statically loading a DLL which is why, if your intention is just to wrap a single legacy component, a regular DLL could be a better choice.

2.5. Example Resolved

Preserving Compatibility

In the example described above there was a need to maintain a target interface, CCommsDatabase, originally implemented by the CommDB component. However this interface needed to work with the new location for the communications database within the Symbian OS Central Repository instead of the old DBMS location. Figure 4 shows the old structure of CommDB.

Figure 4. Legacy structure of CommDB

This problem was solved by removing the old CommDB component and providing a replacement, the adapter, called the CommDB shim which implements the CCommsDatabase interface, the target, in terms of the new communications database component CommsDat, the adaptee. This is possible because CommsDat provides all the functionality of CommDB and more. Figure 5 shows the new structure.

This solution clearly provides source compatibility between the legacy and the new shim implementations of the CCommsDatabase interface since the same class is used in both. Binary compatibility is also preserved by providing the new adapter in a binary with the same name as used in the legacy solution, commdb.dll. However, this doesn't guarantee that the new implementation of the old interface will behave exactly as it used to. The only way to guarantee that this behavioral compatibility has been maintained is to ensure the tests written for the legacy CommDB component work for the new shim version.

Figure 5. Structure of the CommDB Adapter

The result of this is that Symbian OS now has two APIs to one communications database: CCommsDatabase and CMDBSession.

Wrapping Components to Ease Porting

The example described above for this use of the pattern was the porting of SQLite to Symbian OS. The first problem was that, as SQLite is implemented in standard C, it expects a POSIX API to support it from underneath to provide interfaces into the memory model, the file system, and so on. This was solved by using the PIPS[] to provide near-perfect support for the SQLite C calls, requiring little or no tuning of the SQLite code and working 'straight out of the box'.

[] PIPS is POSIX on Symbian (PIPS) is itself a large wrapper for a number of native Symbian OS C++ APIs.

More challenging was providing an interface for use by clients of SQLite. The problem was not that the interface needed to be compatible with the legacy database service, DBMS. Instead the existing interface is written in C and most Symbian OS programmers would expect a Symbian OS C++ API that supports the system-wide functionality, such as platform security as well as backup and restore. So a new interface for Symbian OS, based on C++ was needed.

The key to understanding the final design is to remember that the new interface to SQLite would have to check the security credentials of any clients attempting to access a database. Since this can only be done securely across a process boundary,[] this immediately rules out the use of Client-Thread Service (see page 171) to provide the service interface. Instead, Client–Server (see page 182) was selected to be able to provide a secure service interface to the underlying SQLite component. Accordingly the new component is called the SQL Server. This server provides all the support specific to Symbian OS needed by clients accessing the SQLite library underneath. It resulted in the component structure shown in Figure 6.

Figure 6. Structure of the SQLite Adapter

Run-time Adaptation

Another example of this pattern is provided by the Symbian OS Device Management (DM) subsystem, which supports all aspects of remote provisioning of devices (for example by network operators) to manage device settings. In this case, multiple adapters are required which implement a common provisioning interface CSmlDmAdapter, the target, which is used by the DM client on the handset acting as an agent for a DM server hosted remotely off the device. The adapters map the common target DM interface into various settings interfaces provided by diverse Symbian OS components, for example phone, messaging, and mail.

This gives rise to the structure shown in Figure 7.

Figure 7. Structure of the Device Management Adapter

However, this only partly solves the design problem. Some issues still remain:

  1. Shielding the client from changes in the adaptee with a binary firewall (not just a compilation firewall)[] to reduce any dependencies during development.

    [] This can be achieved to a certain extent with a regular DLL. However, with DLLs one has to supply the module definition (DEF) file to be used by the 'client' at link time. In this case, clearly such a link-time dependency is not suitable.

  2. Keeping track of the number of adapters available on the device.

  3. Loading the appropriate adapter based on the type of settings it supports.

  4. Supporting the addition or removal of adapter implementations to or from the device at run time to allow third-party developers to supply adapters for the DM client.

Here ECom comes to the rescue. By implementing the adapters as ECom plug-ins, the adapters have to be provided in a separate DLL from the DM client, thereby making it completely agnostic of the implementation details or locations of adapters.

Issues 2 and 3 are resolved by ECom's REComSession::List-ImplementationsL() and REComSession::CreateImplementationL() methods, which allow the DM client to specify a 'tag'[] that identifies the plug-ins it is looking for.

[] This 'tag' can be anything, ranging from MIME types to number codes. It is specified in the resource (RSS) file of the ECom Plug-in. Custom ECom resolvers can be designed easily to handle the 'tag'. Alternatively, the implementation UID of the plug-in can be used directly.

Furthermore, the registry of ECom plug-ins is updated whenever a plug-in is added or removed. Clients of the ECom service can register for notification of when this happens, through REComSession::NotifyOnChange(). This is used by the DM Client so that it can maintain an up-to-date list of adapter implementations available on the device, which addresses issue 4.

This example also illustrates how adapters can potentially handle more than one adaptee. Going back to the definition of DM, provisioning a device includes operations such as adding, deleting or modifying various device-level settings. Though there are different types of such settings, each one must support these three main operations. The OMA[] DM provisioning standard defines these as ADD, DELETE and REPLACE 'commands' respectively.


Consider the case of remotely managing the MMS accounts on a device. The MMS framework in Symbian uses two classes to store the details of the MMS accounts:

  • CMmsAccounts is the container for MMS accounts. Each MMS Account item holds the ID and name of the account along with a reference to its MMS Settings object.

  • CMmsSettings holds all the configuration information that is associated with an MMS account. It includes settings such as proxy and IAP settings, delivery notification flags, image specifications, and so on.

To 'ADD' an MMS account, the remote server sends the details via a SyncML message. The DM framework passes the received details and uses ECom to decide that it should be passed on to the MMS adapter (CDmMmsAdapter). CDmMmsAdapter in turn has to deal with both CMmsAccounts and CMmsSettings.

Figure 8 shows a simplified version of how the DM MMS adapter distributes work to its multiple adaptees.

When instructed to create a new MMS account, the CDmMmsAdapter does the following:

// Create a new MMS Settings object
mmsSettings = CMmsSettings::NewL(); // Adaptee 1

// Add this to Settings array

// Ownership transferred

// Device-management house-keeping code

// Create a new MMS account
iMmsAccounts.CreateMMSAccountL(aName, *mmsSettings); // Adaptee 2

This is followed by calls to set (or reset) various MMS Settings parameters (as and when the DM commands arrive), e.g.

// Set an MMS Proxy


// Set delivery notification

Figure 8. Dynamics of the Device Management Adapter pattern

3. Other Known Uses

  • Preserving Compatibility

    A number of features of Symbian OS may be excluded from a device by a device manufacturer, usually because it doesn't have the hardware to support them. For example, this is true of infrared and Bluetooth. However, if the feature is excluded completely then any existing software that uses the feature would fail to compile as the APIs it depends on aren't present. Instead a mechanism is provided to allow existing software to compile and instead check at run time if the feature is present.

    This pattern is used to allow such clients to compile by adapting the target interface of a feature to a non-existent adaptee. The adapter simply provides stubs for the target interface that return KErr-NotSupported. This provides a binary- and source-compatible component for clients to use though, of course, it's not possible to provide behavior compatibility!

  • Porting

    Java, Freetype, and OpenGL have all been ported to Symbian OS using this pattern.

  • Run-time Adapters

    SyncML uses ECom-based adapters to implement an extensible framework for handling multiple transport mechanisms. A number of Transport Connection Adapters (TCAs) exist for the various transport types (HTTP, OBEX over USB, OBEX over Bluetooth, WSP, etc.) and are implemented as ECom plug-ins. This allows device manufacturers to create new adapter plug-ins to add support for new transport mechanisms.

- Mobile Web Apps : Loading Pages (part 3) - Going Backwards
- Mobile Web Apps : Loading Pages (part 2) - Sliding
- Mobile Web Apps : Loading Pages (part 1) - Swapping Pages & Fading with WebKit Animations
- Personalize & Secure Your iPad : Adjusting Sounds on your iPad & Personalize Your Picture Frame
- Personalize & Secure Your iPad : Changing your Lock Screen and Home Screen Wallpapers
- Using Media in XNA Game Studio : Media Enumeration
- Using Media in XNA Game Studio : What Is Media?
- Android Application Development : Layouts (part 2) - AbsoluteLayout & RelativeLayout
- Android Application Development : Layouts (part 1) - inearLayout
- Building an Advanced Java Game on Symbian OS (part 4) - Using the Bluetooth API
Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us
- First look: Apple Watch

- 10 Amazing Tools You Should Be Using with Dropbox

- Sigma 24mm f/1.4 DG HSM Art

- Canon EF11-24mm f/4L USM

- Creative Sound Blaster Roar 2

- Alienware 17 - Dell's Alienware laptops

- Smartwatch : Wellograph

- Xiaomi Redmi 2
Popular tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS
Top 10
- How To Unlock An Account From Active Directory (Windows Server 2008)
- How To Install A deviantArt Theme In Windows 7
- How To Install Windows Server 2012 On VirtualBox
- How To Fix Skype High CPU And Memory Usage In Windows 8
- Add 270 Additional Cleaning Options To CCleaner With CCEnhancer
- FPPT Provides More Than 2000 Free And Attractive PowerPoint Templates
- Setup Free Media Server To Stream Videos To DLNA Compatible TV, Xbox 360 & PS3 (Play Station 3)
- How To Install Android Market & Google Apps On Kindle Fire
- How To Make Ubuntu Look Like Windows 7
- How To Add A New Account in MS Outlook 2013