Wednesday, April 28, 2010

Android kSOAP2 framework

The following code provides a simple kSOAP2 framework for Android bases handsets.  The framework is in the module AndroidkSoap2.  I provies a series of call that allows users to access various web services on the internet.  The code consists of 2 modules,

GetWeather.java -- Andoroid Web Services program that gets current reported weather from a zip code.
AndroidkSoap2.java -- Android Web Services Framework.

There are several other files that include the views, manifest , colors and strings.  You will need to link the kSOAP2 jar file to your program.  The ksoap2 library is called ksoap2-android-assembley-2.4-jar-with-dependencies.jar.  You can find this library in the Android development website.  This should  make your web services life easier with android.


Introduction
kSOAP2 is a stripped down version of SOAP. It contains the necessary methods to build a SOAP object, insert properties, create the SOAP envelope and issue the RPC to the desired website. It also contains methods to recover the returned SOAP object. kSOAP2 allows developers of Android handsets the ability to create Web Services or SOA clients and extract enterprise data from any WS websites.

Group 5.2 has developed a simple kSOAP2 framework that will allow Android developers to easily SOA Web Services client applications for the Android platform. It utilizes the kSOAP2 libraries but allows developer to create a complete web service session with just a single class and 4 methods. It is intuitive utilizing input parameters from the WSDL.


How to Use the kSOAP2 Framework

The framework is easy to use. Simply take the AndroidkSOAP2.java class and include it in your Android package. You will need to link the kSOAP2 library to your project. The library that we used is ksoap2-android-assembly-2.4-jar-withdependencies.jar. This was the latest release as of April 2010. You can get this library from the Android developer’s site and is highlighted in the referenced section in this paper. You will also need to update your manifest with user permissions to enable internet access,

A snippet of code that calls AndroidkSoap2.java follows. It takes you through what is needed to put in your own android code. This snippet of code gets the current weather conditions by zip code.

// Initialize some SOAP Strings

// All of these parameters are gotten from the WSDL

String RequestMethodName = "GetCityWeatherByZIP";

String RequestNameSpace = "http://ws.cdyne.com/WeatherWS/";

String URL = "http://ws.cdyne.com/WeatherWS/Weather.asmx";

String wsVersion = "Ver11";



// Create kSOAP2 Framework Object

AndroidkSoap2 wx = new AndroidkSoap2();



// Initialize SOAP RequestObject

wx.wsSetup(RequestNameSpace, RequestMethodName, wsVersion);



// Stuff SOAP Object with Parameters

wx.wsSetParameters("ZIP", ZipCode)



// Go Get Web Service Return Object and return as a string

String wxString = wx.wsExecuteString(URL);



// Done with framework, now parse the SOAP string





The calls are pretty straight forward. The first is the creation of the AndroidkSoap2 object. This object contains all the necessary soap objects and methods for setup and SOAP internet RPC’s.



AndroidkSoap2 wx = new AndroidkSoap2();



The next method, wsSetup(), sets up the soap object. Here we pass the Namespace, Web Services Method name, and the Web Service Version. These three values are obtained from the WSDL.



wx.wsSetup(RequestNameSpace, RequestMethodName, wsVersion);



Next we stuff the soap object with the necessary parameters. We use the framework method wsSetParameters(). There are two parameters passed, the parameter type and parameter string. These are the parameters required by the SOAP Object. ZipCode is a variable set by user input from the main program GetWeather.java. The parameter type is defined in the WSDL. If you have more than one parameter to stuff into the kSOAP2 object you will have to execute this command several times until you are finished placing all the properties into the SOAP object.



wx.wsSetParameters("ZIP", ZipCode)



Finally we initiate a Web Services request. We use the wsExecuteString() method. Only one parameter is provided, the URL of the Web Service. The returned value for this method is a string version of the SOAP returned object. There is a second wsExecute method called wsExecuteObject() which passes the returned SOAP object. Both are the same object. wsExecuteString() is merely a convenience for converting the WS SOAP object to a string. Most programs will use the string method.



AndroidkSoap2 Framework Definitions

public class AndroidkSoap2() -- Android class that contains all kSOAP2 framework methods. No parameters are passed.



public void wsSetup(String wsNameSpace, String wsMethodName, String wsVer) – kSOAP2 framework method that initializes the kSOAP object.



wsNameSpace Name of Web Service NameSpace. This is provided in the WSDL.

wsMethodName Name of desired Web Service method. This is provided in the WSDL.

wsVer Version of Web Services used at website. This is provided in the WSDL.



public void wsSetParameters(String wsParm1, String wsParm2)— kSOAP2 framework method that places all the necessary parameters in the kSOAP2 object. You may need to execute this multiple times to place all the required parameters in the object


wsParm1 Parameter Type. Provided by the WSDL.

wsParm2 Parameter String. Provided by the WSDL.



public String wsExecuteString(String wsURL) – kSOAP2 framework method that initiates the kSOAP2 RPC command. Returns a string that represents contents of the SOAP object returned from the web service.



public Object wsExecuteObject(String wsURL) – KSOAP2 framework method that initiate the kSOAP2 RPC command. Returns the SOAP object returned from the web service.



wsURL URL of the Web Service.













Android kSOAP2 Web Services Framework Example

Included next is an Android web services example. It is a simple program that takes your zip code and provides the current weather conditions for that area. The code includes the main application along with the resource files. Don’t forget to set internet permissions in the manifest. You will also need to link the kSOAP2 library to your project. Copy this source into the appropriate locations in your Android project and you should be good to go!


GetWeather.java



package fau.edu.getweather;



import fau.edu.getweather.R;

import android.view.View.OnClickListener;

import android.view.View;

import android.widget.TextView;

import android.app.Activity;

import android.os.Bundle;

import android.widget.EditText;

import java.util.regex.Pattern;

import java.util.regex.Matcher;



public class GetWeather extends Activity implements OnClickListener {



// Set up display strings

TextView tv;

EditText zipEditText;

static String ZipCode;

String wxString;



@Override

public void onCreate(Bundle savedInstanceState) {



// Inflate display

super.onCreate(savedInstanceState);

setContentView(R.layout.main);



// Set view id's

tv = (TextView)findViewById(R.id.WXoutput);

zipEditText = (EditText)findViewById(R.id.zipinput);





// Set up click listeners for WX and Exit Buttons

View getWx = findViewById(R.id.go);

getWx.setOnClickListener(this);

View allDone = findViewById(R.id.wxexit);

allDone.setOnClickListener(this);

View allClear = findViewById(R.id.wxclear);

allClear.setOnClickListener(this);



}



// Key Click Handler

public void onClick(View v) {

switch (v.getId()) {



// Exit button pressed, terminate program

case R.id.wxexit:

finish();

break;



// Go button pressed, go get web service weather

case R.id.go:

goGetWX();

break;



// Clear button pressed, clear EditText input fields

case R.id.wxclear:

zipEditText.setText("");

break;

}

}



public void goGetWX() {



// Go get zip code input string

ZipCode = zipEditText.getText().toString();



// Initialize some SOAP Strings

// All of these parameters are gotten from the WSDL

String RequestMethodName = "GetCityWeatherByZIP";

String RequestNameSpace = "http://ws.cdyne.com/WeatherWS/";

String URL = "http://ws.cdyne.com/WeatherWS/Weather.asmx";

String wsVersion = "Ver11";



// Create kSOAP2 Framework Object

AndroidkSoap2 wx = new AndroidkSoap2();



//

//This is where the kSOAP2 Framework is used

//



// Initialize SOAP RequestObject

wx.wsSetup(RequestNameSpace, RequestMethodName, wsVersion);



// Stuff SOAP Object with Parameters

wx.wsSetParameters("ZIP", ZipCode);





// Go Get Web Service Return Object and return as a string

String wxString = wx.wsExecuteString(URL);



//

// Done with framework, now parse the SOAP string

//



// Ok, now let's build the output strings

String screenString = "\n\nCurrent Weather\n" + "\n";

String[] tokens = null;

String splitPattern = ";";

String tempString;



// Get Weather City

Pattern pattern = Pattern.compile("City=.*;");

Matcher matcher = pattern.matcher(wxString);

matcher.find();

tempString = matcher.group();

tokens = tempString.split(splitPattern);

screenString = screenString + tokens[0] + "\n";



// Get Current Conditions

pattern = Pattern.compile("Description=.*;");

matcher = pattern.matcher(wxString);

matcher.find();

tempString = matcher.group();

tokens = tempString.split(splitPattern);

screenString = screenString + tokens[0] + "\n";



// Get Temperature

pattern = Pattern.compile("Temperature=.*;");

matcher = pattern.matcher(wxString);

matcher.find();

tempString = matcher.group();

tokens = tempString.split(splitPattern);

screenString = screenString + tokens[0] + "\n";



// Get Humidity

pattern = Pattern.compile("Humidity=.*; ");

matcher = pattern.matcher(wxString);

matcher.find();

tempString = matcher.group();

tokens = tempString.split(splitPattern);

screenString = screenString + tokens[0] + "\n";



// Get Wind

pattern = Pattern.compile("Wind=.*; ");

matcher = pattern.matcher(wxString);

matcher.find();

tempString = matcher.group();

tokens = tempString.split(splitPattern);

screenString = screenString + tokens[0] + "\n";



// Get Atmospheric Pressure

pattern = Pattern.compile("Pressure=.*; ");

matcher = pattern.matcher(wxString);

matcher.find();

tempString = matcher.group();

tokens = tempString.split(splitPattern);

screenString = screenString + tokens[0] + "\n";



// Print out response

tv.setText(screenString);



}





AndroidkSoap2.java



package fau.edu.getweather;



import org.ksoap2.SoapEnvelope;

import org.ksoap2.serialization.SoapObject;

import org.ksoap2.serialization.SoapSerializationEnvelope;

import org.ksoap2.transport.AndroidHttpTransport;





// kSOAP2 Framework....

// Allows easy integration of web services into any Android application.

// Simply place this class into the same or another package

// You will have to link the kSOAP2 Library to the project

// Use library ksoap2-android-assembly-2.4-jar-with-dependancies.jar

///

public class AndroidkSoap2 {



// Initialize some strings -- Nice and private

private String wsVersion;

private String msDotNet = "asmx";

private String wsString;

private String wsAction;

private Object wsResult;

private SoapObject wsObject;



// Setup SOAP object -- This is the first method you execute

// wsNameSpace -- Web Service Name Space: You get this from the WSDL

// wsMethodName -- Web Service request: You get this from the WSDL

public void wsSetup(String wsNameSpace, String wsMethodName, String wsVer) {



// Create SOAP Object

wsObject = new SoapObject(wsNameSpace, wsMethodName);

// Stuff object with the namespace and the WS request

wsAction = wsNameSpace + wsMethodName;

wsVersion = wsVer;

}





// Stuff the SOAP Object with needed parameters required by the MethodName

// wsParm1 -- Parameter type: You get this from the WSDL

// wsParm2 -- Parameter Value: You get this from the WSDL

public void wsSetParameters(String wsParm1, String wsParm2) {



wsObject.addProperty(wsParm1, wsParm2);

}



// Issue WS request -- This method returns a string of the SOAP object

// wsURL -- URL name of web service site: You get this from the WSDL

public String wsExecuteString(String wsURL) {



// First create the SOAP envelope

SoapSerializationEnvelope soapEnvelope;



// Set which version of SOAP you will be using: Get this from the WSDL

if (wsVersion == "Ver11"){

soapEnvelope = new

SoapSerializationEnvelope(SoapEnvelope.VER11);}

else {

soapEnvelope = new

SoapSerializationEnvelope(SoapEnvelope.VER12);}



// Fix for Microsoft Based WS Sites -- errrrrr!

// If the URL has “.asmx” extension then that’s the bad boy

Integer index = wsURL.lastIndexOf(msDotNet);

if (index >= 0){

soapEnvelope.dotNet = true;}



// Serialized the SOAP Object and stuff it in the envelope

soapEnvelope.setOutputSoapObject(wsObject);



// Create the http RPC Object

AndroidHttpTransport aht = new AndroidHttpTransport(wsURL);

try

{

// Make the SOAP RPC call

aht.call(wsAction, soapEnvelope);

// Get the SOAP Response Object

wsResult = soapEnvelope.getResponse();

// Convert Object to a string

wsString = wsResult.toString();

}

catch(Exception e)

{

e.printStackTrace();

}

// All done, return a string of the response object

return wsString;

}





// Issue WS request -- This method returns a SOAP response Object

// wsURL -- URL name of web service site: You get this from the WSDL

public Object wsExecuteObject(String wsURL) {



// First create the SOAP envelope

SoapSerializationEnvelope soapEnvelope;



// Set which version of SOAP you will be using: Get this from the WSDL

if (wsVersion == "Ver11"){

soapEnvelope = new

SoapSerializationEnvelope(SoapEnvelope.VER11);}

else {

soapEnvelope = new

SoapSerializationEnvelope(SoapEnvelope.VER12);}



// Fix for Microsoft Based WS Sites -- errrrrr!

// If the URL has “.asmx” extension then that’s the bad boy

Integer index = wsURL.lastIndexOf(msDotNet);

if (index >= 0){

soapEnvelope.dotNet = true;}



// Serialized the SOAP Object and stuff it in the envelope

soapEnvelope.setOutputSoapObject(wsObject);



// Create the http RPC Object

AndroidHttpTransport aht = new AndroidHttpTransport(wsURL);

try

{

// Make the SOAP RPC call

aht.call(wsAction, soapEnvelope);

// Get the SOAP Response Object

wsResult = soapEnvelope.getResponse();

}

catch(Exception e)

{

e.printStackTrace();

}

// All Done, return the response object

return wsObject;

}



}

How to build a simple android Web Services Applicaiton

This outline shows how to build a Android web service with kSOAP2.  The outline also includes a simple
java program that is hardwired to go get the latest stock quote for IBM.  Enjoy...

Introduction

kSOAP2 is a stripped down version of SOAP. It contains the necessary methods to build a SOAP object, insert properties, create the SOAP envelope and issue the RPC to the desired website. It also contains methods to recover the returned SOAP object. kSOAP2 allows developers of Android handsets the ability to create Web Services or SOA clients and extract enterprise data from any WS websites.

Standard WS client applications have a characteristic design pattern. The pattern that is emerging is 9 sections dealing with set-up, initialization, build, RPC call, and information extraction. The emerging design patterns follows;

Part 1 -- WSDL Parameter Initialization
Part 2 -- Creation of SOAP Object and WS Request
Part 3 -- Initialization of Request Parameters
Part 4 – Create SOAP RPC Envelope and Serialization
Part 5 – Identify WS Site Technology (.Net or others)
Part 6 – Bind SOAP XML Object to RPC Envelope
Part 7 – Create the HTTP RPC Protocol Object
Part 8 – Make SOAP RPC Call
Part 9 – Extract RPC Response Object

Although a typical WS application will contain much more code than in these examples, the examples represent a typical calling sequence. This code is pretty much self contained and can be integrated with virtually no changes in any Standard WS application.

Part 1 – WSDL Parameter Initialization: This section is line for line exact for both Standard and Extended WS applications. Key variables needed for the kSOAP2 methods are defined here. The key information that is initialized is the NAME_SPACE, METHOD, and URL. All of this information is extracted from the WSDL.

Part 2 -- Creation of SOAP Object and WS Request: The initial SOAP object is created and NAME_SPACE and METHODE are passed. All of this information is gathered by the user from the WSDL.

Part 3 -- Initialization of Request Parameters: The request parameters are added to the SOAP Request Object. The keywords are provided by the user and are extracted from the WSDL. Specific request parameters are provided by the user. In the GetStockQuote example the keyword is “symbol” and the user specific parameters is “IBM”.

Part 4 – Create SOAP RPC Envelope and Serialization: The same for all Standard WS applications.

Part 5 – Identify WS Site Technology (.Net or others): This is a hack to take care of Microsoft .Net WS sites. A URL ending with .asmx indicates that the site has been created with a .Net framework. Set “true” for .asmx WS sites, “false” for all others.

Part 6 – Bind SOAP XML Object to RPC Envelope: The same for all Standard WS applications.

Part 7 – Create the HTTP RPC Protocol Object: The same for all Standard WS applications.

Part 8 – Make SOAP RPC Call: The same for all Standard WS applications

Part 9 – Extract RPC Response Object: Usually the same for all Standard WS applications. I used an object for WS response flexibility. When you use an object you can encapsulate many different return types. This provides better standardization. I am looking at changing this to a Vector() object. Vector() objects provide general encapsulation but also easier string and data management. Give me a couple of days to think about it. The change should be minor and will not affect the previous 8 sections.


Android GetStockQuoteWS.java Example

Below is a working example Android WS application called GetStockQuoteIBM. GetStockQuoteIBM takes a DJIA symbol and builds and XML object. The application then serializes a soap object and makes a request to a WS server. The WS server, http://www.webservicex.net/stockquote.asmx, responses with a SOAP object. Included in the object is substantial company stock trading information. GetStockQuote parses the object and prints out this information. The symbol used is “IBM”, the symbol for International Business Machines, Inc. We will use this simple example as a demonstration vehicle to show how a typical kSOAP2 client is built.




GetStockQuoteIBM.java

package fau.edu.cse;

import android.app.Activity;
import android.os.Bundle;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.AndroidHttpTransport;
import android.widget.TextView;

public class GetStockQuoteIBM extends Activity {

// PART I
// Soap object parameter initialization
// SOAP_ACTION: You build this from "NAMESPACE string" + "METHOD_NAME string"
// METHOD_NAME: User provided, you get this from the wsdl
// NAMESPACE: User provided, you get this from the wsdl
// URL: User provider, you get this from the wsdl
private static final String SOAP_ACTION = "http://www.webserviceX.NET/GetQuote";
private static final String METHOD_NAME = "GetQuote";
private static final String NAMESPACE = "http://www.webserviceX.NET/";
private static final String URL = "http://www.webservicex.net/stockquote.asmx";
TextView tv;

@Override
public void onCreate(Bundle savedInstanceState) {

// Set up the display
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView)findViewById(R.id.TextView01);

// PART 2
// Create and Initialize the SOAP object
SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME);

// PART 3
// Initialize SOAP Parameters to be passed to the Web Service
// User provided, you get this informantion from the wsdl
Request.addProperty("symbol", "IBM");

// PART 4
// Create SOAP Envelope and serialize webservice XML object
SoapSerializationEnvelope soapEnvelope = new
SoapSerializationEnvelope(SoapEnvelope.VER11);

// PART 5
// If URL ends in "asmx" it is a MS .Net site: Set "true"
// If URL ends in something else: Set "false"
soapEnvelope.dotNet = true;

// PART 6
// Bind SOAP request into SOAP envelope
soapEnvelope.setOutputSoapObject(Request);

// PART 7
// Create the HTTP object
AndroidHttpTransport aht = new AndroidHttpTransport(URL);
try
{
// PART 8
// Make the Web Service Call
aht.call(SOAP_ACTION, soapEnvelope);

// PART 9
// Extract the response from the Web Service Object
Object result = soapEnvelope.getResponse();

// Print out response
tv.setText("Quote Results: " + result);
}
catch(Exception e)

{
e.printStackTrace();
}
}
}

main.xml







AndroidManifext.xml
















Using Eclipse lets go ahead and create our project.

























I would recommend that you use an Android 2.1 AVD. You can name the project any name you wish. I used the same name as the program – GetStockQuoteIBM.





















Next you need to link the kSOAP2 library to the application. Right click on the project name “GetStockQuoteIBM”, select “Properties” and then select “Java Build Path”. You will now have this screenshot. Select “Add External JARs…”.























Next select the folder you have the kSOAP2 jar located. The version I am using is ksoap2-android-assembly-2.4-jar-with-dependancies.jar. I found a link from http://code.google.com/p/ksoap2-android/ that pointed to the web location. This is the latest as of April 2010. Select “Open” then “Ok”. If you move the location of the kSOAP2 jar file you will need to re-link the new address location to your project.




















Cut and past the source code into the android “GetStockQuoteIBM” source file. There are a few error flags. Don’t worry we have to update the main.xml and manifest. Don’t forget to save. Also if you chose a different package make sure you update the package name to reflect your new package location.























Cut and paste in the main.xml. We reference TextView01 back I the main program. Don’t forget to save.


























Cut and paste AndroidManifest.xml. Notice the “uses-permission”. This is required if your Android client will be connecting to the internet. Don’t forget to save.


Now build the project and run the android client. You should get the following,






















You have now created your first Android Web Services client application. Although this is a rather simple application almost all Web Services client applications will have pretty much the same structure. Yes, you will have a lot of code in between modifying the display, getting user input, etc. However, the 9 sections will be the remarkably similar.


A word of Caution before You Proceed

kSOAP2 was first developed in 2002 and has undergone several updates. However, it is not a fully fledged version of SOAP. SOAP spends 99% of its time building the XML SOAP object or extracting properties from the received SOAP object. kSOAP2 has limited SOAP object building and property extraction capability. I believe you can eventually build a sufficient SOAP object to talk to any Web Service however many of the facilities in SOAP are missing from kSOAP2 making the task quite difficult. Also extracting the properties from the received SOAP object is problematic without XML object parsing provided by SOAP. kSOAP2 does not provide any XML parsing capability. All of this is normally handled from the output of wsimport. wsimiport is a Apache utility that converts the Web Services WSDL to a set of procedure beans and XML beans. These proc beans enable you to easily stuff the SOAP object. The XML beans allow you to extract the properties for the returned XML SOAP object. kSOAP2 does not support the library requirements of the output from wsimport. SOAP life is difficult without wsimport.

If this is your first introduction I would recommend that you stay away from WS sites that require WS security – Amazon, eBay, etc. kSOAP2 provides no WS security support. You can eventually get kSOAP2 to work with these sites. However, you will require advanced SOAP security knowledge to handle the SOAP security protocol exchange.


Summary

I hope this helps with your first Android WS client application. When I took my first introduction class to Android this document would have saved me 2 weeks of frustration. Good luck.


References

I would recommend a couple of good books on Web Services. Up and running is the definitive book on the introduction to Web Services programming. It moves very quickly so it is intended for more advanced reader. Web Services in 24 hours is more of an introductory and would recommend reading this one first if you have no knowledge of web services. There are a lot more books out there so you have many choices.

Martin Kalin, ISBN 978-0-596-52112-7, “Java Web Services: Up and Running”, 2009
(Be sure to look the errata website: http://oreilly.com/catalog/errata.csp?isbn=9780596521127 )

Stephen Potts, Mike Kopack, ISBN 978-0-672-32515-1, “Web Services in 24 hours”, 2003

There is also an excellent WS introduction video on this website,

http://tv.falafel.com/default/10-02-21/Accessing_NET_Web_Service_from_Android.as