Thursday Jan 03, 2013

ADF Mobile Configuration Service Usage

Overview 

ADF Mobile Configuration Service provides a mechanism for ADF Mobile Apps to update the end-points after they have been deployed to devices. This service allows any end-points configured in connections.xml to be updated on the server and have the deployed Apps uptake the changes without having to go through the normal App update process. All the end-points configured in the connections.xml like Web Service WSDL URI, REST Service URI, LoginServer URI, Remote URL etc can be updated using the Configuration Service.  

Scenarios 

1. Test to Production : When Apps are built they are configured to use dev/test end-points used by the developers for testing during development. Typically these end points are configured by administrators to point to production instances as part of application provisioning. Using Configuration Service allows mobile application administrators to configure the end-points a part of App provisioning.
2. Updating Configuration for Apps in production : In certain cases one may need to change the end points used by an App after deployment to a production environment due to maintenance or some other reason. Configuration Service  & checkForNewConfiguration() API can be used for the configuration changes to be propagated to the mobile apps in production.

Configuration Uptake Flow

First time App start up:

1. When Configuration Service is enabled in an ADF Mobile App, the user is prompted with a dialog to provide the credentials and URI for the Configuration Service. A default URL is populated for the Config Service URL field based on the seeded URL entry in adf-config.xml. User can change this to any end-point provided by the administrator

Config Service Login








































2. After the user enters the credentials and submits the FWK downloads connections.xml from the Configuration Service and restarts the App with the new configuration.

3. During the Application restart the FWK checks for the presence of the downloaded connections.xml and continues with the normal startup flow.

Configuration updates after deployment:  

Developers can use oracle.adfmf.framework.api.AdfmfContainerUtilities.checkForNewConfiguration() API to check if the connections.xml on Configuration Service has changed and if so, download a new version of the connections.xml file from the server. If a new version of the file is downloaded, the application is restarted with the new configuration. Developers can either invoke the API through some UI as shown in the attached sample app or do the check automatically as part of Application or Feature Lifecycle listeners at a certain event point in the App lifecycle.    






































Enabling Configuration Service

Configuration Service can be enabled using the  following configuration in adf-config.xml. This file is in <App root>/.adf/META-INF folder 

<adf:adf-properties-child xmlns="http://xmlns.oracle.com/adf/config/properties">
     <!-- Enable Configuration Service Check at Startup--> 
     <adf-property name="use-configuration-service-at-startup" value="true"/>
     <!-- Seeded Configuration Service URL -->
     <adf-property name="adfmf-configuration-service-seed-url" value="http://192.168.1.9:7101/ConfigService-ViewController-context-root/"/>
</adf:adf-properties-child>


Server Side Configuration Service Setup

Configuration Service can be implemented as a WebDav service or as a Service that accepts HTTP GET and returns connections.xml. The URL used by the Config Service Client is of the following format : <URL Configured in adf-config.xml>/<application bundle id>/connections.xml. The Config Service end-point can be secured using Basic-Auth or Basic-Auth over SSL.

Sample Details

The provided sample application has :
1. ADF MF App (ConfigServiceTest): This App has two features ; 1. remote URL feature pointing to google.com 2. Config feature with a page to check for config changes on the server. The App is configured to check for configuration during initial start-up. The URL used by the remote URL feature is configured in connections.xml. This URL can be changed in the Configuration Service App to point to say, for ex: http://m.bing.com and the mobile app can pick up this change using Config feature. 
2. J2EE app(ConfigService) that contains connections.xml at HTML root/<application bundle id> . This App does not have to be a J2EE App. In fact, it can be any endpoint that accepts HTTP GET and returns connections.xml using the specified URL format. 

Steps to try the sample:

1. Deploy the ADF Mobile App to a simulator or device.
2. Deploy the WAR file to a WLS instance(tested with integrated WLS shipped with JDev 11.1.2.3.0).

3. Start the mobile App. Enter the Config Service URL from step2 in the Config Service dialog displayed during the app startup as shown below. Make sure you change the host and port to point to the WLS instance used in step2.

Config Service Login








































4. The App will download the connections.xml from Config Service and restart.

5. When the App restarts Search feature will display google search page 

Config Service Login






































6. Change the remote URL in connections.xml in the Config Service App to http://m.bing.com. Make sure the changed end point is visible in the connections.xml by accessing the file from a browser
7. In the mobile app, access the Config feature and click on the "Check For Config Changes" button to detect the config change and download the new connections.xml.




































8. The App will restart after downloading the new configuration. This time the search feature will display the bing search page.  






































Config Service Login






































This approach can be used to change any end points used by the app like WSDL URI, REST Service URI, Login Server URI etc.

Wednesday Dec 12, 2012

Configuration Tips for better Performance with ADF Mobile Apps

Some tips to keep in mind to make sure ADF Mobile application's performance is optimal:

1. Select release mode in deployment profile. This is perhaps the most important thing to remember to ensure best performance for ADF Mobile Apps. Selecting this option causes the deployer to package optimized JVM and minified JS libs with the mobile app there by significantly improving the over all performance of the application.

deploy profile

2. For iOS you do not need to do anything else other than selecting  release mode in deploy profile. However, on Android you have to create a keystore and configure it in JDev --> Tools --> Preferences --> ADF Mobile --> Platforms : Android as shown in the snapshot below

android preferences

3. Steps for generating the Keystore for Android using keytool :

keytool





 4. Logging level setting in logging.properties: Make sure the log level is set to SEVERE for both framework logger as well as the application logger as follows

oracle.adfmf.framework.level=SEVERE
oracle.adfmf.application.level=SEVERE

5. When using SOAP WebServices with WebService Data Control make sure you select the option to copy the WSDL. This will cause the JDev to download the WSDL and all the XSDs referenced by the WSDL from the server at design time and package them with the application during deployment. This way the application does not incur the cost of downloading these resources at run time from the device.

wsdc creation



Tuesday Dec 04, 2012

Web Service Example - Part 3: Asynchronous

In this edition of the ADF Mobile blog we'll tackle part 3 of our Web Service examples.  In this posting we'll take a look at firing the web service asynchronously and then filling in the UI when it completes.  This can be useful when you have data on the device in a local store and want to show that to the user while the application uses lazy loading from a web service to load more data.


Getting the sample code:

Just click here to download a zip of the entire project.  You can unzip it and load it into JDeveloper and deploy it either to iOS or Android.  Please follow the previous blog posts if you need help getting JDeveloper or ADF Mobile installed.  Note: This is a different workspace than WS-Part2


What's different?

In this example, when you click the Search button on the Forecast By Zip option, now it takes you directly to the results page, which is initially blank.  When the web service returns a second or two later the data pops into the UI.  If you go back to the search page and hit Search it will again clear the results and invoke the web service asynchronously.  This isn't really that useful for this particular example but it shows an important technique that can be used for other use cases.


How it was done

1)  First we created a new class, ForecastWorker, that implements the Runnable interface.  This is used as our worker class that we create an instance of and pass to a new thread that we create when the Search button is pressed inside the retrieveForecast actionListener handler.  Once the thread is started, the retrieveForecast returns immediately. 

2)  The rest of the code that we had previously in the retrieveForecast method has now been moved to the retrieveForecastAsync.  Note that we've also added synchronized specifiers on both these methods so they are protected from re-entrancy.

3)  The run method of the ForecastWorker class then calls the retrieveForecastAsync method.  This executes the web service code that we had previously, but now on a separate thread so the UI is not locked.  If we had already shown data on the screen it would have appeared before this was invoked.  Note that you do not see a loading indicator either because this is on a separate thread and nothing is blocked.

4)  The last but very important aspect of this method is that once we update data in the collections from the data we retrieve from the web service, we call AdfmfJavaUtilities.flushDataChangeEvents().   We need this because as data is updated in the background thread, those data change events are not propagated to the main thread until you explicitly flush them.  As soon as you do this, the UI will get updated if any changes have been queued.


Summary of Fundamental Changes In This Application

The most fundamental change is that we are invoking and handling our web services in a background thread and updating the UI when the data returns.  This allows an application to provide a better user experience in many cases because data that is already available locally is displayed while lengthy queries or web service calls can be done in the background and the UI updated when they return.  There are many different use cases for background threads and this is just one example of optimizing the user experience and generating a better mobile application. 


Tuesday Nov 06, 2012

Web Services Example - Part 2: Programmatic

In this edition of the ADF Mobile blog we'll tackle part 2 of our Web Service examples.  In this posting we'll take a look at using a SOAP Web Service but calling it programmatically in code and parsing the return into a bean.


Getting the sample code:

Just click here to download a zip of the entire project.  You can unzip it and load it into JDeveloper and deploy it either to iOS or Android.  Please follow the previous blog posts if you need help getting JDeveloper or ADF Mobile installed.  Note: This is a different workspace than WS-Part1


Defining our Web Service:

Just like our first installment, we are using the same public weather forecast web service provided free by CDYNE Corporation.  Sometimes this service goes down so please ensure you know it's up before reporting this example isn't working.

We're going to concentrate on the same two web service methods, GetCityForecastByZIP and GetWeatherInformation.


Defing the Application:

The application setup is identical to the Weather1 version.  There are some improvements to the data that is displayed as part of this example though.  Now we are able to show the associated image along with each forecast line when using the Forecast By Zip feature.  We've also added the temperature Hi/Low values into the UI.


Summary of Fundamental Changes In This Application

The most fundamental change is that we're binding the UI to the Bean Data Controls instead of directly to the Web Service Data Controls.  This gives us much more flexibility to control the shape of the data and allows us to do caching of the data outside of the Web Service.  This way if your application is, say offline, your bean could still populate with data from a local cache and still show you some UI as opposed to completely failing because you don't have any connectivity. In general we promote this type of programming technique with ADF Mobile to insulate your application from any issues with network connectivity.


What's different with this example?

We have setup the Web Service DC the same way but now we have managed beans to process the data.  The following classes define the "Model" of our application:  CityInformation->CityForecast->Forecast, WeatherInformation->WeatherDescription.  We use WeatherBean for UI interaction to the model layer.  If you look through this example, we don't really do that much with the java code except use it to grab the image URL from the weather description.  In a more realistic example, you might be using some JDBC classes to persist the data to a local database.

To have a good architecture it is always good to keep your model and UI layers separate.  This gets muddied if you start to use bindings on a page invoked from Java code and this java code starts to become your "model" layer.  Since bindings are page specific, your model layer starts to become entwined with your UI.  Not good!  To help with this, we've added some utility functions that let you invoke DC methods without having a binding and thus execute methods from your "model" layer without requiring a binding in your page definition.  We do this with the invokeDataControlMethod of the AdfmfJavaUtilities class.  An example of this method call is available in line 95 of WeatherInformation.java and line 93 of CityInformation.Java.


What's a GenericType?

Because Web Service Data Controls (and also URL Data Controls AKA REST) use generic name/value pairs to define their structure and don't have strongly typed objects, these are actually stored internally as GenericType objects.  The GenericType class is simply a property map of name/value pairs that can be hierarchical.  There are methods like getAttribute where you supply the index of the attribute or it's string property name.  Why is this important to know?  Because invokeDataControlMethod returns GenericType objects and developers either need to parse these GenericType objects themselves or use one of our helper functions.


GenericTypeBeanSerializationHelper

This class does exactly what it's name implies.  It's a helper class for developers to aid in serialization of GenericTypes to/from java objects.  This is extremely handy if you have a large GenericType object with many attributes (or you're just lazy like me!) and you just want to parse it out into a real java object you can use more easily.  Here you would use the fromGenericType method.  This method takes the class of the Java object you wish to return and the GenericType as parameters.  The method then parses through each attribute in the GenericType and uses reflection to set that same attribute in the Java class.  Then the method returns that new object of the class you specified.  This is obviously very handy to avoid a lot of shuffling code between GenericType and your own Java classes.  The reverse method, toGenericType is also available when you want to go the other way.  In this case you supply the string that represents the package location in the DataControl definition (Example: "MyDC.myParams.MyCollection") and then pass in the Java object you have that holds the data and a GenericType is returned to you.  Again, it will use reflection to calculate the attributes that match between the java class and the GenericType and call the getters/setters on those.


Issues and Possible Improvements:

In the next installment we'll show you how to make your web service calls asynchronously so your UI will fill dynamically when the service call returns but in the meantime you show the data you have locally in your bean fed from some local cache.  This gives your users instant delivery of some data while you fetch other data in the background.

Friday Nov 02, 2012

Web Services Example - Part 1: Declarative

In this edition of the ADF Mobile blog we'll tackle part 1 of our Web Service examples. In this posting we'll take a look at using a declarative SOAP Web Service.


Getting the sample code:

Just click here to download a zip of the entire project. You can unzip it and load it into JDeveloper and deploy it either to iOS or Android. Please follow the previous blog posts if you need help getting JDeveloper or ADF Mobile installed.


Defining our Web Service:

First off, we should mention that this sample code is using a public web service provided free by CDYNE Corporation that provides weather forecasts by zipcode. Sometimes this service goes down so please ensure you know it's up before reporting this example isn't working.

Let's take a look at the web service.  We created this by using the "Web Service Data Control" from the New Gallery and using this link to this wsdl:  "http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"   This web service has several methods but we're interested in GetCityForecastByZIP which takes a single string parameter for the zipcode and the second method, GetWeatherInformation that enumerates all possible forecast descriptions and associated image URLs.  The latter we'll use in the next edition but we included it here for completeness.


Defing the Application:

After adding a feature to the adfmf-feature.xml file, we added a taskflow to host the application flow.  This comprises of a home screen with a list with items for each method in the web service, "Forecast by Zip" and "Weather Info".  In this application we've also decided to hide the navigation bar since there is only one feature in the application.


Forecast by Zip:

The "Forecast By ZIP" option first presents the user with a screen where they can enter a zipcode and when the "Search" button is tapped, it executes the GetCityForecastByZIP method.  This is done by binding an Action binding to that method. The easiest way to accomplish this is to just drag & drop the method from the Data Control palette to the AMX page and drop it as a button and let the framework hook it up for you.  There is an inputText component on the page that is bound to a pageFlowScope variable called "zip".  This is used as the parameter to the Action binding when it is executed.  Because the actionListener attribute of the commandButton executes the Web Service each time, we ensure that the method is invoked every time the button is clicked.


Weather Info:

Unlike the previous method, this time instead of explictly executing the web service method we are using deferred invocation.  What this means is that we will bind to the results of the method and the framework will execute the method when it the data is required to be rendered.  We do this by simply doing a drag & drop of the results of the GetWeatherInformation to the AMX page.  When the page is rendered and the bindings are resolved the framework invokes the method.  This executes the method only when it is needed and fills the Data Control provider.  Because we never re-execute the method, you can click from Home to Weather Info and back many times and the web service is only ever invoked once.


Issues and Possible Improvements:

One thing you will quickly realize with this example is that the error handling is done by the framework for you. For simple examples this is fine but for real applications you'll want to customize these error messages.  With the declarative invocation of web services, this is difficult.  This is one aspect we'll address in the second installment of the web service examples where we will show you how to do programmatic invocation which allows you better error handling.

Another issue you will notice with this example is that we can enumerate the weather information but there isn't an easy way to use that information to show the corresponding description and image as part of the forecast results.  We'll show you how to do this in the next example.

About

This blog is is dedicated to tips and tricks for developing, integrating, securing, and managing mobile applications using Oracle Mobile Platform. It is created and maintained by the Mobile Suite/Oracle ADF Mobile product development team.

Archive of past entries

Even More Mobile Development Blogs

Oracle A-Team Site - Mobile Related Entries

Code samples from the Community

Fusion Middleware Blogs

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today