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.