OraclePermissionGeneratorAndroid is an example of a simple Android-based business application, implementing the MVP (Model View Presenter) design pattern, and demonstrating how an Android application can interact with a .NET WCF webservice via SOAP or REST protocols.
Mobile devices already represent a major slice of the personal computing landscape, as users move from PCs to phones and tablets. A similar transition is occurring also in enterprise/business computing, where many companies have already adopted BYOD (bring your own device) policies, and are deploying mobile-capable software for staff. It's natural that this transition will continue and accelerate in the future. As an engineer of enterprise software, I felt it was essential to get some exposure to development on a mobile device platform. Android has the largest installation base of any operating system, and is used by over 20,000 unique types of devices (current as of 2015). Given that it's easily accessible to developers (freely available SDK and IDEs) I decided to develop a simple Android application to get some experience on a mobile platform.
In 2013 I released a .NET / Windows Forms application called Oracle Permission Generator. This was a simple desktop application which allowed users create and manage user permission scripts for Oracle databases. My goal in writing a mobile application was to create a version of Oracle Permission Generator for the Android platform. The original version of Oracle Permission Generator was built using the MVP (Model View Presenter) design pattern which meant that all the business logic (the Model part of the pattern) was clearly separated from the user interface code. I wanted to reuse the original .NET business logic (MVP Model) code unaltered, exposing it as a webservice via WCF, and reimplement the View and Presenter components as an Android application.
In the past I had written several desktop applications using the MVP pattern. Although it can take time to understand, and can seem overly complex for simple applications, I had grown to really like the MVP pattern because of the following benefits...
Given this experience, and as my Android project would be a GUI application, it was a natural choice to use the MVP pattern.
See the instructions for installing and opening the projects.
This section gives a brief overview of the main Android components and classes that are required to build a basic application.
An Activity in Android is an abstract component representing 'a single, focused thing that the user can do'... it can basically be through of as a single screen in an Android application, somewhat analogous to a Form in Windows Forms, or a Window in Java AWT/Swing. The AddRoleToUserMapActivity class in OraclePermissionGeneratorAndroid is a good example of a simple Activity.
A Service is a component in an application which does not have a user interface, and is used to implement long-running background tasks. There are two sub-types of services...
In OraclePermissionGeneratorAndroid (hereafter referred to as 'OPG Android'), the Android-side Model layer (which proxies business logic / data layer method calls to the C# webservice) is implemented using a bound service (in class datainterfacelayer.DataInterfaceService).
View is a superclass of many of the UI components which can be placed on Activities (similar to 'Controls' or 'Widgets' in other GUI frameworks). Examples include TextView, ListView, EditText, Spinner, and Button. As an example, the AddRoleToUserMapActivity mentioned above contains 3 TextViews, 2 EditTexts, and a Button. ViewGroups are used to define collections and arrangements of Views.
An Intent is a somewhat abstractly-named class which has many uses in Android applications. In OPG Android they are used to...
XML is used fairly extensively in Android projects...
An Android project also includes a master 'AndroidManifest.xml' file which contains many fundamental application settings.
An Android project contains an R class which is generated by the compiler. This class provides a 'bridge' between pure Java classes (e.g. Activities), and classes that are defined in the XML files (e.g. Views defined in the 'res\layout\' folder). The R class is located in the 'gen\' folder of an Android project.
There is a lot of information available online about the MVP pattern, but the basic principle of the pattern is to separate the business logic and user interface concerns (as is also the case with other 'MV' patterns like MVC and MVVM). Business logic and domain model concerns are part of the Model layer of the pattern. User interface concerns form the View layer. The presenter is basically the 'glue' between the View and the Model and controls all interactions and data passing between them. Clear interfaces are defined for each of the 3 layers.
By virtue of enforcing these separations of concern, and having interfaces defined for each of the layers, it's easy to write very unit testable code using MVP. The idea is to make the code in the View(s) as simple as possible, so that unit tests are not required around this layer (as user interface components are typically difficult to unit test). Any control flow code in the application should be incorporated into the presenter, and business logic and domain model code into the model. As the presenter and model don't contain any UI components, it's straightforward to write unit tests around them.
The sequence diagram below shows the interactions (i.e. method calls) between the 3 layers when the user clicks the 'Add Mapping' button in the 'Add Role to User Mapping' screen (class AddRoleToUserMapActivity) in OPG Android. This sequence of interactions between the layers is typical for an MVP application. The key point is that there is no direct interaction between the Views and the Model... all such interaction is handled by the Presenter...
In OPG Android, each of the 3 MVP layers have the following responsibility...
In line with the MVP paradigms, the View layer is kept as simple as possible. Views are implemented as Android Acitvities. Methods to manipulate the UI (e.g. populate a field) usually just pass data directly to a subclass of the Android View*. Interactions with the UI (e.g. intercepting button clicks) are generally just passed directly to methods on the Presenter.
As well as managing interactions between with View and Model layers, the Presenter in OPG Android handles the following...
* Note that the term 'View' here is used in two different contexts... the MVP View layer (an abstract grouping of code which provides the user interface), and the Android View class (a superclass in the Android API which is a building block for user interface components). The term will be used in both contexts throughout this document, so it's important to understand the distinction.
The diagram below gives an overview of the main classes in OPG Android, and where they fit into the MVP pattern...
There are some fundamental differences between the MVP pattern and some of the practices that are advocated and demonstrated in the Android API and sample projects on the web. These are summarised below...
Practice | MVP | Android API / Samples |
---|---|---|
Data passing between activities | All data is passed through the Presenter | Data is passed directly from one Activity to another using Intents |
Access the to domain model / business logic | Channelled through the Presenter | Activities access domain model / business logic directly (e.g via an Android Service) |
Exception handing and control flow code | Implemented in the Presenter | Implemented in Activites (code can potentially be reused by putting common code in base Actvities) |
The Android Intent class is used to start Activities from other Activities. The Intent class includes a method putExtra() which allows name/value data pairs to be passed to the Activity being started. The value of the name/value pairs can be primitive data types, arrays of primitive data types, or classes implementing the android.os.Parcelable or java.io.Serializable interfaces (essentially objects that can be serialized). Using the Intent.putExtra() method to pass data between activities is demonstrated by many Android sample projects on the web. However this is contrary to the MVP pattern where Views should not communicate directly with other Views, and all data should be passed via the Presenter.
Many Android sample projects access their domain model and business logic by having Activities connect directly to Android Services. This also breaks the MVP paradigm, where all access to the domain model and business logic should be channelled through the Presenter. Similarly many Android sample projects implement exception handling and control flow via code in Activities (examples of control flow are often Activities starting other Activities as described above). In MVP control flow is handled by the Presenter. Exception handling would usually be managed by either the Presenter or the Model layers in MVP (in OPG Android I chose to implement it in the Presenter).
The diagram below gives an overview of component interactions as demonstrated in many Android sample projects...
...whereas this depicts the same interactions using the MVP pattern applied to the Android framework...
In the MVP pattern, the relationship between a View and Presenter is bi-directional. This allows interactions to occur from the Presenter to the View (e.g. populating fields in the view) and also from the View to the Presenter (e.g. handing a user action like a button click). To implement this bi-directional relationship a reference to the Presenter class is required from the View and vice-versa. In languages and frameworks where the creation of UI classes is explicitly controlled by the programmer, implementing such a relationship is straightforward. The Java sample below shows how a UI class could be created and have a reference to the Presenter class set on it (assuming MainView is a subclass of javax.swing.JDialog)...
In Android, the creation of new Activities is instead effectively sent to the Android operating system as an Asynchronous request (via an Intent). As a result there is no straightforward way for the code creating the Intent to get a reference to the new Activity that is created as a result of the request. The Intent class has the putExtra() method (discussed above) which can send data to new activities, but this is limited to sending primitive data types and serializable classes (essentially it can pass copies of data, but not references to classes). Hence there isn't a straighfoward way to create a reference from the View to the Presenter equivalent to the above Java code. I considered three possible ways to work around this...
I steered away from implementing the Presenter as an Android Service, mainly because Services can be subject to forced shutdown if the Android OS is low on memory. As the Presenter is the central component in the application, having to recreate it during runtime would mean re-establishing a lot of reference to Views (Activities) which would potentially introduce a lot of additional complexity. I generally try to avoid using singletons if possible, so I was not keen on implementing the Presenter as a singleton (also doing this could have created extra complexity in unit testing... e.g. how could I call a special constructor on the Presenter to pass in the mocks used for the unit testing case, if it was implicitly created as a singleton?). I settled on the third option to use a separate singleton class to hold a reference to the presenter. This meant the Presenter class could still be instantiated explicitly, and instantiated with a special constructor for the unit test case, but also a reference to the Presenter could be obtained from the singleton class. I created a simple singleton called PresenterGlobalStorer to hold the presenter...
Then to get a reference to the Presenter from an Activity, I access the PresenterGlobalStorer from the Activities' onCreate() method. The below example is from the AddRoleToUserMapActivity class (note the 'presenter' member is defined in the BaseActivity superclass)...
The onCreate() method is called by the Android OS as part of the process of creating a new Activity from an Intent. Hence following the above pattern results in the correct bi-directional relationship with the Presenter being established each time a new Activity is created.
Working with the Android Activity lifecycle provided another challenge. A key point is that the Android OS has the ability to kill an Activity to recoup system memory. As references are maintained between Activities (MVP Views) and the Presenter, my concern was that the reference from the Presenter to an Activity could delay or prevent garbage collection of killed Activities, or potentially create 'orphaned' Activities which were still accessed by the Presenter, but which the Android OS considered to be closed or killed. To attempt to avoid these situations, I overrode the onDestroy() method in each Activity (this method is called by Android before killing any Activity as part of the Activity lifecycle), and reset the reference from the Presenter. The below code is a sample of the AddRoleToUserMapActivity class (again the 'presenter' member is defined in the BaseActivity superclass)...
I hoped that would avoid any issues with preventing garbage collection or creating 'orphaned' Activties (but have not as yet done extensive testing of the application's interaction with the Activity lifecycle).
The original Windows Forms version of Oracle Permission Generator was a single user application. I wanted to reuse the original business logic (Model) code, but also support multiple users in the Android version. Most of the key business logic and domain model functionality was encapsulated in a class called OraclePermissionGeneratorDataInterfaceLayer (a class composing several more granular areas of functionality and exposing them following the facade pattern). The simple approach I took to implementing multi-user functionality, was to create a .NET Dictionary where the dictionary value was an OraclePermissionGeneratorDataInterfaceLayer class, and the key was a string representing a unique id for a user. This allowed each unique user to access their own copy of the data model. This Dictionary is created in the Program class, and injected into the SoapWebServiceApi and RestWebServiceApi classes which expose the Model layer via SOAP and REST respectively...
Generally, the SoapWebServiceApi and RestWebServiceApi classes simply proxy method calls to the relevant OraclePermissionGeneratorDataInterfaceLayer object in the Dictionary (this is mostly performed by base class WebServiceApiBase). As an example, the code to add a new mapping between a role and user appears below (member 'userDataRepository' is the Dictionary class)...
For the purposes of a simple prototype, this Dictionary solution for multiple users is sufficient. However for real production code it couldn't be used for the following reasons...
Most consumer applications written for Android and other mobile platforms like IOS follow an asynchronous design paradigm. Responses to user interaction are processed in the background, and the user interface remains fully operational at this time, potentially allowing for additional background operations to be processed in parallel. This type of paradigm does introduce some extra complexity though. Say for example the connection to the server is lost whilst a background operation is being processed... the UI may have already been updated anticpating the operation would be successful (e.g. adding a new item to a list), and the user may have moved on to another operation (like updating the new item). In the case the background operation fails, the UI and server side get out of sync, and some mechanism is required to resolve this. Applications often use client-side caching of operations to handle these types of cases (i.e. the operation can be cached in the device and synchronised with the server when the connection becomes available again). However, what happens if the loss of connection cannot be resolved in time... e.g. if there are dependencies on the new item being sent to the server within a specified timeframe? You could elect to notify the user of the failure to synchronize after a set timeout/retry period, but what if the user was no longer using the device when that notification came? Ofcourse mechanisms can be built to work around and solve these problems, but they make the process of interacting with the server inherently more complex.
My goal with this project was to build an Android application for a business context. Often for these types of applications, having the possibility of a failure notification being missed is not an option. As a basic example, say in a financial markets trading application the user inputted a trade, but due to a connection issue the trade didn't go through, and the user wasn't immediately notified... such a situation could result in financial loss and hence wouldn't be acceptable to the user. So for that reason I chose to adopt a more synchronous paradigm for OPG Android. When a background process with the server is started, the user interface is blocked (preventing further user interaction) until one of the following situations eventuates...
This type of paradigm has some drawbacks, most significantly...
... however it does mean that the outcome of any server interaction can be more deterministic, and more reliable, which is better suited to enterprise/business applications.
For consumer applications an asynchronous approach is usually preferable. Some patterns to implement asynchronous service interaction are discussed in this presentation from Google I/O.
Much like other application frameworks which support a GUI, Android requires that any interaction with the user interface be done from the main thread of the application. To allow long running processes (like accessing webservices over the internet) to execute on a worker thread and then update the user interface on the main thread, the Android API provides a class called AsyncTask. The AsyncTask class provides similar interface and functionality to the BackgroundWorker class in the .NET framework. In other frameworks it's possible to execute long running processes on the application's main thread (at the expense of potentially making the user interface unresponsive), however in Android long running tasks must be executed on a worker thread. The Android OS constantly monitors applications for responsiveness of the user interface, and if it detects that an application is unresponsive, it will show an 'Application Not Responding' dialog and prompt the user to close the application. The OS monitors applications frequently, and these 'Application Not Responding' dialogs show very quickly if long running tasks are executed on the main thread.
In OPG Android, all long running processes followed the same pattern of operation...
Additionally, any access to the C# webservice was dependent on the availability of a network connection, so I wanted to be able to handle the case of the device being disconnected, and give the user the option to retry when the connection was available. Finally, in the case of an unexpected exception occurring, I wanted to display a 'friendly' message to the user, and store details of the exception on the device. I wrote a subclass of AsyncTask called ExceptionHandlingAsyncTask which manages worker threads and provides the following additional functionality...
As the ExceptionHandlingAsyncTask class is only used by the Presenter, it's implemented as an inner class inside the Presenter. The class facilitates most of OPG Android's basic functionality. The below code gives an example of using the ExceptionHandlingAsyncTask to add a role to user mapping to the application...
One of my goals with OPG Android was demonstrate multiple methods of communicating with a webservice, namely REST/JSON and SOAP/XML as the means of transport protocol and data serialization respectively. Since REST/JSON was already implemented in many other Android applications, I started with the SOAP/XML webservice.
Given there were already comprehensive Java libraries available for hosting and consuming web services, at the very start of the project (before having setup the Android libraries, IDE, etc...) I started building Java code to consume a SOAP .NET webservice using Apache CXF framework. I spent a fair amount of time on this, before porting code over to Android, and realizing it wouldn't compile! An important distinction to understand is that Oracle Java and Android Java are not the same... aside from running on different underlying Java virtual machines, some packages (specifically parts of javax which are required by CXF) are not included as part of Android Java. Support for consuming SOAP webservices is available in Android using the ksoap2 library.
Ksoap2 is an open source package which allows you to consume SOAP webservices in Android. To connect to webservices, and send SOAP messages using ksoap2 is relatively straightforward. However to serialize and deserialze to/from Java objects and XML using ksoap2 is somewhat tedious, requiring that you manually iterate through an XML document and build your Java objects by extracting data from the document. It requires a lot more bespoke code as compared to CXF (where a pre-compilation step builds the serialization/deserialization code for you), and given there were quite a number of container objects in OPG Android, I was reluctant to spend too much time on writing a lot of custom serialization code. Comparitively, the org.json package which is included with Android for serialization/deserialization to and from JSON objects allows this type of serialization code to be built more simply. So for that reason I decided to use SOAP as the transport protocol, but JSON (rather than the usual XML) for object serialization.
The Model layer of the application (containing the business logic and domain model) was implemented as an Android service. As most of the Model layer function sends webservice requests to the .NET version of the Model layer, it suited the design intention of the Android service... i.e. to perform long running background operations without a user interface. The Model layer is implemented in class datainterfacelayer.DataInterfaceService (note, as this class effectively aggregates all of the business logic, domain model, and hence MVP Model functionality of the application, I will refer to it as the 'data layer' of the application going forward). In order to function correctly as an Android service, DataInterfaceService subclasses the Android Service class and includes the following...
For the Presenter to connect to the DataInterfaceService, it must do so through a subclass of the Android ServiceConnection class. This subclass should override the onServiceConnected() and onServiceDisconnected() methods, and in case of OPG Android I wanted to set a reference from the Presenter to the DataInterfaceService when the DataInterfaceService was started/connected. As such, I implemented the class DataInterfaceServiceConnection as an inner class of the Presenter...
The actual creation of the connection/binding from the Presenter to the DataInterfaceService occurs in the Presenter's private method CheckDataInterfaceServiceConnection(), which is called as the first step in any Presenter method which needs to connect to the data layer. The DataInterfaceService is actually started by first creating an Intent, and then passing that Intent and a reference to the DataInterfaceServiceConnection class to the bindService() method on the main Activity of the application (ObjectListActivity). Having a dependency on an Activity (actually an Android Context which is a superclass of Activity) is a little unfortunate, as it doesn't work well with the MVP pattern. As per the pattern, the Presenter does not hold view references as concrete Activity classes, but rather interfaces. This means that to access the Context classes' methods, the view reference must be cast to a Context. This can subsequently cause problems with unit tests where the view references are mocks rather than concrete Activities/Contexts. Furthermore, from the MVP theory perspective, the pattern is supposed to enforce separation between the View and Model components. By creating a coupling between them in the bindService() call, it breaks the MVP paradigm and has the potential to also impact other benefits that the pattern offers (like unit testing as mentioned). Unfortunately there's no avoiding this in the Android API, as a Context object is required to be able to start or bind to a Service. The full code of the CheckDataInterfaceServiceConnection() method appears below...
There's a couple of undesirable (but unfortunately unavoidable) practices in this method. The first is the thread spinning while waiting for the Service to be started. This relates to the synchronous vs asynchronous paradigms discussed above. Android is primarily asynchronous in behaviour, however in this case, immediately after binding to the Service, I want to use methods in the data layer to set the protocol to use (SOAP or REST). Even in the absence of this requirement, the code calling the CheckDataInterfaceServiceConnection() method could want to call methods in the data layer at any time after binding to perform its basic function. Hence, I decided to spin wait until the 'dataInterfaceServiceConnected' flag is set (which is set when the DataInterfaceServiceConnection.onServiceConnected() method is called). As the CheckDataInterfaceServiceConnection() method is generally called from a worker thread (i.e. from the doInBackground() method of the ExceptionHandlingAsyncTask class), the thread spinning whilst not good practice, doesn't result in problems with 'Application Not Responding' dialogs.
The second point which could be improved is the call to Context.unbindService() at the end of the method. This means that immediately after starting the DataInterfaceService, there is nothing bound to it. I did because I experienced issues with 'Activity has leaked ServiceConnection' errors when closing the ObjectListActivity. In theory it means the Android OS could elect to shutdown the service at any time, although I never experienced issues with this in testing (however, granted I didn't do any testing with a device with high memory usage). In retrospect it probably would have been better to call the unbindService() method via the Presenter from the ObjectListActivity's onDestroy() method. I may make this change to the code in a future release.
As discussed above, I wanted to support the option of either SOAP or REST protocols to connect to the C# data layer. The diagram below shows how this dual support is implemented...
The DataInterfaceService exposes a setter method for a class implementing interface IRemoteDataModelProxy. Any of the DataInterfaceService public methods which need to access the C# webservice, are internally proxied to the IRemoteDataModelProxy class, which takes care of the actual data transport. There are 2 provided implementations of the IRemoteDataModelProxy interface, SoapRemoteDataModelProxy and RestRemoteDataModelProxy (facilitiating the connection to C# via SOAP and REST respectively).
Note that there are 2 parameters which are passed to all of the public C# webservice methods (in both SOAP and REST implementations)... the 'authenticationContext' and 'trackingData' parameters. 'authenticationContext' is used to pass user identification data to the webservice, and 'trackingData' is used to pass tracking information about the hosting device (location and network IP address). These parameters essentially hold metadata relating to each method call, and ideally should not be explicitly passed every time in the method signature. Particularly with the 'trackingData', a future improvement would be to use a more sophisticated authentication mechanism (connection-level or token based) which would eliminate the need to send it with every method call.
The SoapRemoteDataModelProxy class uses the ksoap2 library to facilitate a connection to the C# webservice via SOAP. Most of the work is done in private method MakeSoapRequest()...
The following class diagram shows the relationships between classes and interfaces that expose the data layer of the application as a C# / WCF webservice.
Interface ISoapWebServiceApi uses WCF OperationContract attributes to define the methods that are exposed via SOAP, for example the GetMasterRoleToUserMapCollection() method which returns the complete list of role to use mappings defined in the data layer...
Note that although the implementation of this method in the underlying data layer returns a list of RoleToUserMap objects, in the ISoapWebServiceApi interface this method (and all other methods) return and accept just strings. As discussed above due to the limited support for XML serialization in Android, I decided to make the SOAP webservice handle JSON data types rather than XML, so passing all parameters as strings allows custom code to convert the strings to and from JSON objects. As an example, the implementation of the GetMasterRoleToUserMapCollection() method in the SoapWebServiceApi class, calls the WebServiceApiBase class to process the method, a List<RoleToUserMap> object is returned, and this is serialized to a JSON string...
The Android RestRemoteDataModelProxy class facilitates connecting to the WCF webservice via REST. The Android API does not include a REST client library, and whilst there are several third party libraries available, I decided to create my own rest client code inside the RestRemoteDataModelProxy class by creating the relevant URLS, and using the HTTP functionality in the org.apache.http package. Private method CreateRestUrl() is used to create a REST compatible URL...
The various types of REST methods are called using private methods MakeGetRequest(), MakePutRequest(), MakePostRequest(), and MakeDeleteRequest(). The code for MakeGetRequest() appears below...
On the C# side, the IRestWebServiceApi interface uses the OperationContract, WebGet, and WebInvoke attributes to define the methods exposed by REST, and how they are exposed. Through the WebGet and WebInvoke attributes, WCF can automatically handle serialization and deserialization of JSON parameters (via the RequestFormat and ResponseFormat properties) hence the RestWebServiceApi class which implements the interface doesn't require custom serialization code like the equivalent SOAP class does.
This project was my first experience with designing a REST API end to end. It requires a different approach to more traditional remote procedure call APIs, and there are many good web resources on building proper 'RESTful' APIs. I found this article on MSDN really useful, not least because it's specifically geared towards building REST webservices using WCF.
Moving from Verbs to Nouns - Probably the most fundamental concept to grasp when building a REST API is the change for having an unlimited number of 'verbs' to define, to being restricted to the verbs offered by HTTP and therefore by REST... i.e. GET, PUT, POST, DELETE, etc... For methods like GetRoles(), the REST implementation is straightforward... an HTTP GET method with a URL path '/Roles'. However, to implement methods like ObjectTypeValidate() requires a little more thought (here the verb 'validate' doesn't fit with the methods offered by HTTP). In this case I changed the paradigm from 'validating an object type' to 'getting a validation for an object type', and hence the method was implemented as an HTTP GET with a URL path '/Validations/ObjectType/[object type parameter]'. There were several cases where I had to adjust the 'perspective' of the data layer methods in this way, in order to get them to fit into the verbs available in REST.
WebInvoke.WebMessageBodyStyle Property - WCF exposes a property WebMessageBodyStyle on the WebInvoke attribute. For methods with JSON parameters, this attribute defines whether the parameters in the request and/or response messages should be wrapped with JSON notation. For example the GetDefaultObjectOwner() method with the default 'Bare' WebMessageBodyStyle returns the default object owner as a raw string...
...however setting BodyStyle = WebMessageBodyStyle.WrappedResponse wraps the returned string in JSON notation as follows...
At runtime, WCF tries to map the parameters of the method to parameters defined in the UriTemplate property of the WebInvoke attribute. Any parameters which do not map are assumed to be part of the request body. For example the AddRoleToUserMap() method has the following definition...
Both the 'authenticationContext' and 'trackingData' parameters are defined in the UriTemplate, leaving the 'role' and 'user' parameters to be included in the message body. However, using the default 'Bare' WebMessageBodyStyle means there is no mechanism of differentiate between the two parameters in the message (having a single parameter in the body is allowed using the 'Bare' style, but not any more), and will result in the following exception...
Hence for methods like AddRoleToUserMap() with multiple body parameters, the BodyStyle must be set as wrapped. An example of correctly wrapped message body parameters for the AddRoleToUserMap() method appears below...
Correct HTTP Headers for PUT and POST Methods - For PUT and POST methods to be properly processed by WCF, the following HTTP header string must by set on the request messages...
This is implemented in the MakePutRequest() and MakePostRequest() methods in the Android RestRemoteDataModelProxy class...
DELETE Methods and Idempotency - According to the strict definition of REST, DELETE methods should be idempotent, meaning that if for example a DELETE method is called to remove an entity that has already been removed or doesn't exist, the method should not return an error. However, the data layer of the original Windows Forms version of the application was designed to throw an exception in such cases (e.g. if the RemoveRoleToUserMap() method was called for a role to user mapping which didn't exist). Rather than override the original functionality I chose to leave it throw an exception in these cases, but it does mean that the REST interface doesn't strictly follow REST principles in this regard.
POST vs PUT for Inserts - The HTTP PUT method is designed to be used to create or update a resource. The AddRoleToUserMap() method in the C# webservice is used to create a role to user mapping, and hence by this definition should use the PUT method. However, PUT method calls are supposed to be idempotent (as for DELETE methods described above), and the AddRoleToUserMap() will return an error if called with a mapping which already exists. Rather than break REST principles by using the PUT method, I elected instead to use the POST method, which is design for more generic usage and does not need to be idempotent. The same applies to the AddObjectPermissionSet() and AddPermission() methods.
Sending 'authenticationContext' and 'trackingData' as Query Parameters - Any parameters which are defined in the UriTemplate property have to be of type string. The 'authenticationContext' and 'trackingData' parameters are complex container objects, and are passed with every method call to provide user identification and tracking data associated with the device making the webservice request. I had to think about the correct way to include these parameters in the REST interface. Rather than being part of the application data model, they are really just metadata passed with each method call. Hence I didn't think they belonged in the path section of the UriTemplate, which is more used for entities which are part of the data model (like '/Validations/ObjectName/' or '/PrivilegeScripts/Rollout'). I decided instead to put them in the query parameters section of the UriTemplate as this is typically used for optional or additional information in REST interfaces. However to comply with the restriction that parameters in the UriTemplate must be strings, both parameters are defined in the method signatures as strings, but are explicitly deserialized to the relevant objects in the WebServiceApiBase class.
REST Method Definitions - This page contains a full list of the public methods in the data layer, and their corresponding REST implementation.
To expose the data layer through SOAP and REST webservices simultaneously, I create 2 instances of the ServiceHost class, which expose the methods defined in the SoapWebServiceApi and RestWebServiceApi classes (and hence the ISoapWebServiceApi and IRestWebServiceApi interfaces) via WCF. So that both webservices act on the same data layer instance, the Dictionary of OraclePermissionGeneratorDataInterfaceLayer objects (explained above) is injected into the constructors of both WebServiceApi classes.
One caveat with using 2 ServiceHost instances, is that the SOAP and REST webservices have to listen on different ports (in this case 5000 and 5001). If required it would be possible to expose both SOAP and REST on a single ServiceHost instance and port. However, separate method signatures for SOAP and REST would have to be defined in a single interface, e.g. something like the following...
Notice the REST version of the method has to include the 'Rest' suffix to prevent a definition clash with the SOAP version. In my case I preferred to maintain cleaner method names at the expense of having to run the webservices on separate ports, but if running on a single port was a requirement the above technique could be used.
Implementing the same API using both SOAP and REST gave a good opportunity to compare the details of each protocol side by side. The message samples below show the raw HTTP request and response messages sent by SOAP and REST for the RoleToUserMapValidate() method...
In this section I'll run through the implementation of a simple Activity in Android end-to-end using the MVP pattern. I'll use the AddRoleToUserMapActivity Activity as an example as its interaction with the Presenter and Model layers is outlined in the sequence diagram discussed earlier. The Activity allows the user to define a new mapping between an Oracle database role and user account, and click a button to add that mapping to the data layer...
The diagram below shows all classes which must be created or modified in order to implement the Activity's functionality end to end, and the layer of the MVP pattern to which they belong...
The Activity needs to call 2 methods in the data layer... RoleToUserMapValidate() and AddRoleToUserMap(). These methods must be defined in the ISoapWebServiceApi and IRestWebServiceApi interfaces...
The methods should be implemented in the SoapWebServiceApi and RestWebServiceApi classes, which simply proxy the methods calls to the WebServiceApiBase class. The WebServiceApiBase class then calls the relevant methods in the OraclePermissionGeneratorDataInterfaceLayer class from the original Windows Forms version of the application...
The 2 methods need to be available in the Android-side DataInterfaceService class. As the implementation of these methods is provided to the DataInterfaceService class by the SoapRemoteDataModelProxy and RestRemoteDataModelProxy classes, the two methods must be implemented in each of these classes...
The layout of user interface items (fields, labels, buttons, etc...) in an Android Activity are defined through an XML file in the res/layout/ folder of the Android project. I won't go into detail of the content of the XML here, as there are many good online resources on the subject (and it's also possible to build the Activity using a WYSIWYG designer in Eclipse). However a small sample of the layout for the AddRoleToUserMapActivity appears below...
The AddRoleToUserMapActivity Java code includes a handler for the 'Add Mapping' button, and importantly establishes a link to the Presenter class in the onCreate() method. This method also contains code to setup the appearance of the Activity according to the previously defined XML layout file (by calling method setContentView())...
Note that this Activity implements interface IAddRoleToUserMapView, so that it can easily be mocked when unit testing the presenter. In following the paradigm of MVP, all views in the application (and hence all Activities) should implement an interface.
After implementing the Model and View components of the pattern, the Presenter acts as the 'glue' betweeen these layers. It must perform two functions. The first is to allow a mechanism to display the AddRoleToUserMapActivity. This is implemented in the ShowAddRoleToUserMapView() method...
As this method doesn't require any access to the data layer (or other long running operation), it doesn't need to use the ASyncTask class, and simply opens the AddRoleToUserMapActivity via an Intent.
The second function is to handle when the user clicks the 'Add Mapping' button in the AddRoleToUserMapActivity. This is handled by Presenter method AddRoleToUserMap(), and as the method needs to access the data layer, it uses the ASyncTask class to do so. In an instance of the ExceptionHandlingAsyncTask class, the doInBackground() method is overridden to validate the role and user using the DataInterfaceService.RoleToUserMapValidate() method. If the validation returns as successful, the DataInterfaceService.AddRoleToUserMap() method is called to add the new mapping, and regardless of success or failure the result of the validation is sent back to the main application thread...
The subsequent action on the main application thread is defined by overriding the ExceptionHandlingAsyncTask.onPostExecute() method. If the validation was successful, the new role to user mapping is added to the RoleToUserMapActivity (which is the parent Activity of AddRoleToUserMapActivity and will be open behind it), and then the AddRoleToUserMapActivity is closed. If the validation failed, an alert dialog is displayed, showing the reason for the failure...
I implemented fairly extensive unit tests for the project using the typical unit testing paradigm for MVP applications... i.e. tests are included for the Presenter and Model components, whilst the Views are kept simple and hence don't require unit tests. Unit testing for Android, at the time I started this project, had a few differences from and disadvantages compared to unit testing of a standard Java project...
That said, more recently Android unit tests have improved some of these earlier problems, and have been better integrated into Android Studio including...
The success test for the Presenter.AddRoleToUserMap() method is shown below. As the Presenter manages worker threads via the ASyncTask class, a mechanism was needed to ensure that the worker thread tasks were completed before verifications and assertions were performed in the tests. To facilitate this a 'test' constructor is defined on the Presenter, which allows injecting of a CountDownLatch object...
In the test code, the await() method is called on this CountDownLatch object before asserting the results of the test...
Note that the unit tests are split between two projects... 'OraclePermissionGenerator.AndroidUnitTests' and 'OraclePermissionGenerator.UnitTests'. The former tests classes which have a dependence on the Android API, and hence must be run through Eclipse as 'Android JUnit Tests'. The plain 'UnitTests' project contains classes which contain just standard Java code, and hence can be run as 'JUnit Tests' (and hence run much more quickly).
Tracking information containing the Android host device's location an IP address is passed to the C# webservice with every method call. By default, the webservice logs this information to a text file using the FileTrackingDataLogger class. Additionally, since version 0.10.0.0 of OPG Android classes are available to log this information to either a DynamoDB or Redshift instance on Amazon Web Services.
This page explains the setup process and prerequisites for using DynamoDB and Redshift.
To log to DynamoDB (via the AwsDynamoDbTrackingDataLogger class), change the initialization section of the C# Program class as follows...
... or for Redshift, use the following code...
Note that the AwsRedshiftTrackingDataLogger class needs to be explicitly connected and then disconnected from the Redshift database instance.
Both classes access the relevant AWS service as part of the webservice method call, which is fine for a prototype case. However in real production code, the tracking data should be queued and sent to AWS in batches (by a separate thread, process, or server), to minimize the webservice's response time to a method call.
There are a few fundamental Android concepts and components I used, which are well documented in Android's documentation and other online tutorials. These are listed below with a reference to the classes or components within OPG Android which show an example of them...
After having successfully finished OPG Android using MVP (and having had to workaround some of the problems I faced in doing so), I was interested in seeing my approach and code compared to implementing the same functionality using the more commonly advocated method of putting the MVP Presenter functionality directly in each Activity class. I created the net.alastairwyse.oraclepermissiongenerator.activitytest package, to reimplement the RoleToUserMapActivity without using the Presenter and compare the result to the MVP version in terms of separation of concerns, ease of unit testing, etc... This is currently a work in progress.
After having completed the application using the MVP pattern, looking back there are a few alternative approaches which would have yielded a different result, and could be further investigated and compared to the current design...
The source code for the project is available on GitHub.
JavaDoc documentation for the Android Java code.
Lars Vogel's Android Tutorials - these provide an excellent practical reference for many of the fundamental concepts regarding building Android applications.
Android REST client applications from Google I/O 2010. A little bit dated now, but suggests some patterns for implementing asynchronous/cached connections to REST webservices.
I presented many of the ideas from this page to colleagues in a series of training sessions. The powerpoint presentations from these sessions are available here and here.
Feel free to contact me via the details here with any questions or comments.