Wednesday, September 12, 2012

SOAP for Android

As you know Android does not support SOAP. The reason for that might be, SOAP is complicated on mobile clients. Generating code from WSDL is cumbersome and finally communicating in SOAP means more network traffic which is something to consider in hand-held devices. As a result using REST with JSON is a sensible approach. Because, its flexible in data type returns. JSON is lightweight and simple to parse. JSON is the preferred method of data interchange on hand-held devices.

Still if you have to use SOAP, here are couple of examples using ksoap2 . Ksoap2 is an API for SOAP on Android.

Example 1

This could be an example of primitive return type in ksoap2.

Lets assume we have to authenticate to a system before calling any business web methods. After authentication the system will give us valid JSESSIONID.  The target system provides a web method from which we can login then,  it will return us valid JSESSIONID. This id will be send along with any further method calls to identify us as a valid user.

You can see how to pass primitive data to a web method and parse primitive result from that.

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import android.util.Log;

public class LoginUtil {
    //Name of the method we want to call
    public static String METHOD_NAME = "login";
    public static String SOAP_ACTION = NAMESPACE + METHOD_NAME;
    //The name space (you can get this from WSDL)
    public static String NAMESPACE = "http://webservice.web.security.com/";

    public static String lognToThesystem(String username,String password, String host, String port) {
       SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);       
        //Setting the property to be passed to the web service method
        PropertyInfo propInfoUsername = new PropertyInfo();
        propInfoUsername.name = "arg0";
        propInfoUsername.type = PropertyInfo.STRING_CLASS;

        request.addProperty(propInfoUsername, username);
       //Setting the property to be passed to the web service method      
        PropertyInfo propInfoPassword = new PropertyInfo();
        propInfoPassword.name = "arg1";
        propInfoPassword.type = PropertyInfo.STRING_CLASS;

        request.addProperty(propInfoPassword, password);

        String url = "http://" + host + ":" + port + "/app/ws/login?wsdl";
      
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.setOutputSoapObject(request);

        HttpTransportSE androidHttpTransport = new HttpTransportSE(url);
        SoapPrimitive resultsRequestSOAP = null;
        try {
            androidHttpTransport.call(SOAP_ACTION, envelope);
            //Since we know the result is of type primitive then, cast it to SoapPrimitive
            resultsRequestSOAP = (SoapPrimitive) envelope.getResponse();
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
        }
        return resultsRequestSOAP == null ? "" : resultsRequestSOAP.toString();
    }
}

Example 2

Now we are going to look at a more complex example. In the previous example we obtained a JSESSIONID. We want to call a method (getAllUsers) but we have to provide the JSESSIONID with this request otherwise the system wont let us call the aforementioned method. The return type of this request call is not primitive and consists of complex objects. This method returns all the users with the condition that  if any of their properties have changed between fromDate and toDate (this is just the business rule). The constructor of this class receives all the necessary data needed for this method call.

You can see how to pass Date to a web service method and parse a list of objects return from that. Also you can see how to add a header property to the request.

Return type object:

public class WebServiceEntity {
    private long id;
    private String name;
    private int type;
   
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
}

Caller class:

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Vector;

import org.ksoap2.HeaderProperty;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.MarshalDate;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.util.Log;

import com.vahid.dto.WebServiceEntity;

public class GeneralRecords {
    private final String NAMESPACE = "http://webservice.web.vahid.com/";
    private final String METHOD_NAME = "getAllUsers";
    private final String SOAP_ACTION = NAMESPACE + METHOD_NAME;
    private String jsessionId;
    private String url;
    private Date fromDate;
    private Date toDate;
    private Vector<SoapObject> result = null;
  
    public GeneralRecords(String jsessionId,String host, String port, Date fromDate, Date toDate) {
        this.jsessionId = jsessionId;
        this.fromDate = fromDate;
        this.toDate = toDate;
        this.url = "http://" + host + ":" + port + "/service/vahid/general?wsdl";
    }

public List<WebServiceEntity> getAllEntiites() {
        //Create a soap object
        SoapObject soapObject = new SoapObject(NAMESPACE, MethodName);
       //Defining the fromDate property
        PropertyInfo propFromCal = new PropertyInfo();
        propFromCal.name = "arg0";
        propFromCal.type = MarshalDate.DATE_CLASS;
      
        soapObject.addProperty(propFromCal, fromDate);
        //Defining the toDate property
        PropertyInfo propToCal = new PropertyInfo();
        propToCal.name = "arg1";
        propToCal.type = MarshalDate.DATE_CLASS;

        soapObject.addProperty(propToCal, toDate);
      
         SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
         envelope.setOutputSoapObject(soapObject);
//Use MaeshalDate so that the system knows how to serialize and deserialize objects you are trying to pass through the web service
         MarshalDate md = new MarshalDate();
         md.register(envelope);
     
         //Make the call to target web service
         HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
         Object response = null;
         try {
             //Create a list and assign all the necessary header properties. In our case we only need JSESSIONID
             List headers = new ArrayList();
             HeaderProperty jsessionIdProperty = new HeaderProperty("Cookie", "JSESSIONID="     +            jsessionId);
             headers.add(jsessionIdProperty);
             androidHttpTransport.call(SOAP_ACTION, envelope, headers);
             response = envelope.getResponse();
         } catch (Exception e) {
             Log.e("Error", e.getMessage());
         }

         if (response instanceof SoapObject) {
             result = new Vector();
             result.add((SoapObject) response);
         } else if (response instanceof Vector) {
             result = (Vector<SoapObject>) response;
         }
         //Retrieve object from soap
         List<WebServiceEntity> webServiceEntity = new ArrayList<WebServiceEntity>();
         for (SoapObject soap : result) {
             WebServiceEntity wse = new WebServiceEntity();
             wse.setId(Long.parseLong(soap.getProperty(0).toString()));
             wse.setName(soap.getProperty(1).toString());
             wse.setType(Integer.parseInt(soap.getProperty(2).toString()));
             webServiceEntity.add(wse);
         }
         return webServiceEntity;
    }
}

Monday, August 20, 2012

Android testing framework - Robotium


Robotium is an Android UI testing framework designed to simplify black-box testing. The framework supports almost all Android related classes such as Activities, Dialogs, Menus, etc. Robotium can be seen as a supplementary to JUnit when you want to automate your tests for Android applications.

When using Robotium, the framework interacts directly with the emulator. It just like if a real user is using your software. You can create the steps for getting the result, identify the expected result and finally, assert the outcome.

There is another testing framework called Robolectric. This framework does not need an emulator to be present. It contains implementation of Android SDK within itself. This speeds up the testing process.

Now, an example using Robotium.

Lets create a sample ui with 2 EditTexts and one DatePicker.
Assume that we have to fill these 2 editTexts and set the calendar to January 1 2011.

Create a class which extends ActivityInstrumentationTestCase2. This class give you the capability to setup a fully functional runtime environment.

Create a no argument constructor and call the super constructor with the Activity under test.

 ActivityInstrumentationTestCase2 defines activity under test which is, in this example MainActivity
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity>

private Solo solo;

public MainActivityTest(){
        super(MainActivity.class);
}

Create a Solo object in setUp method.

@Override 
protected void setUp() throws Exception {
        super.setUp();
By using the method below we can get a reference to the activity under test and starting it if necessary.
        currentActivity = getActivity();
Access Robotium using solo object instantiate it by passing instrumentation and the activity under test
        solo = new Solo(getInstrumentation(), currentActivity);
}

Create a test method for filling the UI.

public void testFillMainActivityUi(){
         String text1 = "first editText";
         String text2 = "second editText";
         get a reference to editTexts
         EditText editText1 = (EditText) currentActivity.findViewById(R.id.editText1);
         EditText editText2 = (EditText) currentActivity.findViewById(R.id.editText2);
        set text for both editTexts
        solo.enterText(editText1, text1);
        solo.enterText(editText2, text2);
        get a reference to datePicker
        DatePicker datePicker = (DatePicker)currentActivity.findViewById(R.id.datePicker1);
        set datePicker value to first Jan 2011 (month starts from zero)
        solo.setDatePicker(datePicker, 2011, 0, 1);
        assert the result
        Assert.assertEquals(text1, editText1.getText().toString());
        Assert.assertEquals(text2, editText2.getText().toString());


        Assert.assertEquals(2011, datePicker.getYear());
        Assert.assertEquals(0, datePicker.getMonth());
        Assert.assertEquals(1, datePicker.getDayOfMonth());
}

Wednesday, July 18, 2012

Android Development Tools plugin for eclipse conflicting dependancy issue

When you are trying to install Android Development Tools (ADT) plugin for eclipse you might face with an error like "Cannot complete the install because of a conflicting dependency".



You can rectify this issue first by trying to run Check for updates in eclipse (above image). Most probably you will get a list of components needing update. Try to update each listed module one by one. After each successful update try to install ADT plugin again until you can successfully install it. For example, after successful update of "Eclipse IDE for Java Developers" I was able to install ADT plugin. The update process fixes the conflict dependency.

Sunday, July 15, 2012

Scrum, a new hope!

A long time ago in this universe not far away....
 A new hope!
 It’s the period of customer unrest. Most of the time development team is behind schedule. Product management department nagging all the time. Sales department promote a feature and promises on time release without development team having even the slightest clue what is the feature....

 Our company’s main methodology for software development is RUP.

 The whole thing started when a former colleague paid a visit. In our discussion he pointed out that they are developing based on Scrum. That was the start of the whole thing. Maybe that's the path to salvation for us! Salvation from what? Well, our customers were not satisfied by the way we delivered the change requests. The reason for that was, most of the new features were developed and delivered in one big iteration of 6 month to 1 year after the user had initiated the change request.
Although that delivery was a big release with many features but it was quite late. Time to market was the big issue. A very important factor fostering this late delivery was complication and the scope of the requested feature. Most of the time we miss calculate the actual time needed for the development. This miss calculation was the key for late delivery.

Common understanding can mitigate the risks involved in the production. Although we could have continued with RUP and tried to go through the elaboration phase more accurately but we decided to move to Scrum for the reasons I'm going to discuss.



We are now in our second sprint. Well, if I want to give you a summary of what we experienced in our first sprint I should say we failed to break down each user story into small tasks with maximum 16 hours per task allocation. We had tasks of about 40 hours. This was an indication that this task was composed of many smaller tasks and we should have broken it down. The burn down chart always showed us the deviation which was not acceptable.

There were also some positive result as well. For example, we collaborated with one another more often. Communication between team members flourished. And the last thing that we enjoyed was pair programming. By programming in pairs we shared our knowledge, we were more active and somehow we almost doubled our speed in some areas.

Overall, for the first sprint it was quite good experience.


If I want to conclude I should say there is much less stress in our team. We have high level of collaboration. By looking at the story board we can instantly know the state of the project. In our daily standup's everybody know about the state of each task. If there a complication in each task people can share and seek help. By this way, we can avoid move on faster.  Burn down chart represent how much work is left and how well we are progressing.

   

Wednesday, July 11, 2012

Location Finder - My first experience with Android

I started my career as a Java EE developer. Recently, my attention was drawn to the domain of hand-held devices. That was intriguing for me . Well, being a Java developer Android was a fine choice. 
I began by:
  • Learning the basics
  • Developing a project with Android
    • Define the boundaries of the project
    • Code and test
After spending some time on the basics I decided to get my hands dirty. My project is called Location Finder.

Objective:
  • Pinpointing all the points of interest in a radius given by the user on a map. Point of interest could be a specific keyword such as restaurant or a more broad one such as food which might include restaurants, confectioneries or etc.
  • All points of interest should be clickable. After clicking the overlaid icons, name and address of the place must be shown in a dialog box to the user.
So, my choice was a program capable of advising a user of nearest point of interest.

For this project I used 2 API's from Google. Google Map, Google Places and of course GPS on the device. There are so many good tutorials on how to integrate Google map into your code so I'm not going to delve in to that. I think this is sufficient to say that you have to sign up with the service and include a key in your View in order to use Google map services. That key is given by Google.

Business process is demonstrated below:
Diagram 1-Location finder activity diagram
  The diagram is created by Violet uml editor.

MainController class loads my main layout. It incorporates a very simple UI with one EditText,  a SeekBar and 2 TextViews acting as labels. Finally we have 2 Buttons (Find and Cancel). The design is depicted in the class diagram.


Diagram 2-Location finder class diagram

When the find button is clicked an Intent triggers the onCreate method of GMapActivity. The detail can be followed on the diagram 3 which is one possible sequence diagram of this application.
Diagram 3-Location finder sequence diagram

Source Code:

Monday, July 9, 2012

Android, emulator control is disabled under devices section of Dalvik Debug Monitor Server (DDMS) in eclipse

Problem :
Sometimes you can't communicate with your running emulator  although its up and running. There is nothing listed under "Devices" section of the DDMS view in eclipse. The "Location controls" section under Emulator control is also disabled. 

Why you need that ? For example, you want to have your location using GPS on your emulator. That can be achieved by simulating GPS coordinates using DDMS view > Emulator Control > Location Controls. There you can assign longitude and latitude.

Solution:
Try listing your running processes on your computer. On Mac you can use "Activity monitor". There you can find a process named "adb" (Android debug bridge). When you find it, kill the process and watch your eclipse console output for following message:

[2012-07-09 19:16:16 - DeviceMonitor] Connection attempts: 1

After few attempts you should have your connection to the emulator back. There should be an emulator listed under devices sections automatically.

Tuesday, July 3, 2012

A complication with embedding Axis2 in a webapp

There was a need to develop a web service in our web project in order to make it interoperable with other system specially written in languages other than Java. We had number of options to choose from such as Metro which is part of GlashFish Community and Axis2 which is from The Apache Software Foundation.
We carried out a memory test. We developed a class with a method returning a byte[10000000] worth of data. Then exposing them with both Metro and Axis2. Our web service clients called the services in a loop of 100 with Thread.Sleep(1000) in between of each call. With the aid of VisualVM which offers JVM profiling and monitoring we monitored the memory usage and garbage collection. Both services were used just out of the box (without any additional configuration and tuning). They were almost the same in terms of memory usage. Annotation is the beauty of Metro. If you have your class then your are 2 steps from making your class act as a service. First annotate the class with @WebService and second annotate a method with @WebMethod. That's All. Isn't it easy!
 Here is a simple guide Building a simple Metro application you can give it a try.

With regard to ease of use, Axis2 was a bit problematic. I'm going to explain more on the problem and the approach I took to solve it.

The problem:

When my class was ready, I added axis2 Servlet to web.xml. Then,  exposing the class by adding service.xml to the folder hierarchy under WEB-INF as:
WEB-INF
     |---->services
       |---->myApp
         |---->META-INF
           |---->service.xml

 service.xml defines the the description of the service. At the final step, I tried to add all the necessary jar files to the classpath of the server. Everything seemed ok but the service was not deployed. There was no error in the logs. I checked my service by trying to checkout the WSDL on the browser. The response was an error indicating "No service is available at this URL" or "The service cannot be found for the endpoint reference (EPR) " without any further clue or any other exceptions on the server.

The solution:

 axis2-web is a "collection of JSPs that make up the Axis2 administration application "

I tried to list my service by using axis2-web at the address below by deploying the application in my Servlet engine.

http://address:port/context/services/listServices

After calling the address above I found out there is a missing class causing malfunction. Although nothing was in the log files indicating ClassNotFoundException