Sunday, March 6, 2011

Calling a Java SOAP Web-service from Android and iOS apps - Part 1

Objective of this series of tutorials is to:
  • Create a SOAP web-service to convert a temperature in Fahrenheit to Celsius in Java using Eclipse, Tomcat and Axis
  • Create and Android app that uses ksoap2 library to call the web-service and shows the result on screen.
  • Create and iPhone (iOS) app that calls the same web-service and shows the result on screen.
In this part I will show hot to build the web-service from ground up.

Pre-requisites:
3. Axis2 1.4.1 (I had trouble with the latest version)

Once both Tomcat and Axis2 have been configured in Eclipse Workspace, go ahead and create a Dynamic Web Project as follows:
























Add a new Class called Temperature to Java Resources of your project:

package org.ushasoft;
import java.text.DecimalFormat;
public class Temperature {
private static final DecimalFormat TWO_D_FORM = new DecimalFormat("#.#");
public String Convert(String fahrenheit) {
try {
double f = Double.parseDouble(fahrenheit);
//return Double.toString( TWO_D_FORM.format(((f - 32) * 5)/9));
return TWO_D_FORM.format(((f - 32) * 5)/9);
} catch (Exception e) {
return "Invalid";
}
}
}

Save the file, then select this newly created class and right click on it, Select "Web Services" from the context menu and then "Create Web Service" 



































Make sure all of the parameters are set accordingly and just go through the subsequent screens, selecting default values everywhere.






































Once the Web-service has been generated and deployed to Tomcat, Launch the Web Services Explorer (it's under "Run" menu when you're in Java EE perspective)

Select the Web Page option and paste the WSDL URL 
 http://localhost:8080/Temperature/services/Temperature?wsdl and hit Go

You should be able to test your Web-service with an input:
































So, we have our Service working. Let's get the Android app going.

First of, you will need the ksoap2 library for Android, download the latest jar from here.
I'm assuming you have Android SDK already installed for Eclipse.

Now switch over to Java perspective and create a new Android Project :










































Add INTERNET permission to your Android App Manifest, you will need that to make the Web-service call.

Update the main.xml in "res/layout" folder of your project as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" 
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:padding="30dip">
    <TableLayout android:stretchColumns="*" android:layout_width="fill_parent" android:layout_height="wrap_content">
     <TableRow android:layout_width="fill_parent" android:layout_height="wrap_content">
     <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" 
     android:textStyle="bold" android:text="@string/label_fahrenheit" android:padding="5dip"/>
     <EditText android:id="@+id/inputFahrenheit" android:layout_width="wrap_content" 
     android:layout_height="wrap_content" android:imeOptions="actionDone" android:inputType="number"/>
     </TableRow>
     <TableRow android:layout_width="fill_parent" android:layout_height="wrap_content">
     <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" 
     android:textStyle="bold" android:text="@string/label_celsius" android:padding="5dip"/>
     <EditText android:id="@+id/txtCelsius" android:layout_width="wrap_content" android:layout_height="wrap_content" 
     android:inputType="none" android:editable="false" />
     </TableRow>
     <TableRow android:layout_width="fill_parent" android:layout_height="wrap_content">
     <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/>
     <Button android:id="@+id/btnConvert" android:text="Convert" 
     android:layout_width="wrap_content" android:layout_height="wrap_content"/>
     </TableRow>
    </TableLayout>
</LinearLayout>

And your Activity class should like the following:

package org.ushasoft.temperature;
import java.io.IOException;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class ConverterActivity extends Activity {
    /** Called when the activity is first created. */
TextView inputFahrenheit;
TextView txtCelsius;
Button btnConvert;
public final static String URL = "http://10.0.2.2:8080/Temperature/services/Temperature?wsdl";
public static final String NAMESPACE = "http://ushasoft.org";
public static final String SOAP_ACTION_PREFIX = "/";
private static final String METHOD = "Convert";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        inputFahrenheit = (TextView) findViewById(R.id.inputFahrenheit);
        txtCelsius = (TextView) findViewById(R.id.txtCelsius);
        btnConvert = (Button) findViewById(R.id.btnConvert);
        
        btnConvert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doConvert();
}
});
    }
    private void doConvert() {
     if (inputFahrenheit.getText() == null || inputFahrenheit.getText().toString().length() == 0) {
     return;
     }
     SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
SoapObject request = new SoapObject(NAMESPACE, METHOD);
request.addProperty("fahrenheit", inputFahrenheit.getText().toString());
envelope.bodyOut = request;
HttpTransportSE transport = new HttpTransportSE(URL);
try {
transport.call(NAMESPACE + SOAP_ACTION_PREFIX + METHOD, envelope);
} catch (IOException e) {
e.printStackTrace();
System.out.println("SOAP Error : " + e.getMessage());
System.out.println("SOAP Response : " + transport.responseDump);
} catch (XmlPullParserException e) {
e.printStackTrace();
System.out.println("SOAP Error : " + e.getMessage());
System.out.println("SOAP Response : " + transport.responseDump);
}
if (envelope.bodyIn != null) {
SoapPrimitive resultSOAP = (SoapPrimitive)((SoapObject)envelope.bodyIn).getProperty(0);
txtCelsius.setText(resultSOAP.toString());
}
    }
}

That's pretty much it. Run the application and it should work as shown:































You can download the source code below:



2 comments:

Govindarajan said...

Nice article, I'm trying to do some thing simillar, was wondering how will the client connect to the service running on a PC via 3G network. It works fine when both of them are in the same wifi network. any thoughts?

Kaushal said...

You should look @ http://www.dyndns.com/

they provide free dynamic DNS service, that way you can use Host names instead of ip address in your service calls and it will work even if you're not in the same WiFi network.