First steps in creating your web service enabled mobile application using JSON, Geronimo, Android and RESTEasy

This articles will reveal the first steps in setting up your development environment for building WebService/Enterprise Java applications and consuming their services from Android device. What I am using in this example:

  • Geronimo with Jetty7 javaee5 – 2.2.1 – as application/web server
  • Eclipse Indigo EE (with WTP plugin)
  • Android SDK 4.0.3
  • Google Gson 2.1
  • Resteasy – jaxrs – 2.3.1.GA

Please don’t be bored from so many screenshots. If you know the basics you just can skip them. Please also don’t try to rewrite any code from them – source code is available for download at the end of the article.

So first step is to download and setup all these packages. If you are new to Java – then you should start by downloading Java 6 or Java 7 from Oracle Download site.

The proceed with Eclipse EE – download site.

Get Android and follow the instructions to install it and add ADT plugin to your Eclipse IDE.

Download and unpack Google GSon, Reaseasy and Geronimo.

And now is where the fun starts.

The Web Service

First we will create a web application with one simple webservice that will serve JSON data. I suppose at this step that you have setup your Eclipse and integrated it with Geronimo. (if you have troubles with finding information, please consult with the link to Geronimo 2.2 documentation).

Start Eclipse EE and create your Geronimo server – goto server tab in the bottom panel, righ-click and select New -> Server:

Select the location that you have extracted Geronimo server in:

Create a new Web -> Dynamic Web Project.

Set the web project name and make sure to select target server to Apache Geronimo server that you have created

Now we should import Resteasy libraries into our Web Project – just get the libs from the location that you have extracted resteasy package and drop them into WebContent\WEB-INF\lib folder in package explorer. When asked – select “Copy” files.

Here comes the fun part.
Let’s code the classes. We shall begin with the data container object for our data exchange. We shall create a simple bean (MsgObj) that will contain 2 attributes – id and msgText.

package com.npenkov.testweb;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "msg")
public class MsgObj {
	private int id;
	private String msgText;

	@XmlAttribute
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}

	@XmlAttribute
	public String getMsgText() {
		return msgText;
	}
	public void setMsgText(String msgText) {
		this.msgText = msgText;
	}
}

As we have out container, now we shall create the Service class. It will contain just one simple method that will return a new instance of our MsgObj with some data in it.

package com.npenkov.testweb;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/first")
@Consumes({"application/json"})
@Produces({"application/json"})
public class FirstService {

	@GET
	@Path("/tellMe")
	public MsgObj tellMe() {
		MsgObj m = new MsgObj();
		m.setId(1);
		m.setMsgText("Hello, friend!");
		return m;
	}
}

Important for web service (resteasy) is to create the so called Application class, that will know what services we should expose. It is mandatory that it extends javax.ws.rs.core.Application. You should mention here in the constructor that we add our service class to list of web service classes that Application will provide.

package com.npenkov.testweb;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;

public class WebServicesApp extends Application {
	HashSet<Object> singletons = new HashSet<Object>();

	public WebServicesApp() {
		singletons.add(new FirstService());
	}

	@Override
	public Set<Class<?>> getClasses() {
		HashSet<Class<?>> set = new HashSet<Class<?>>();
		return set;
	}

	@Override
	public Set<Object> getSingletons() {
		return singletons;
	}
}

Time for setting the web.xml descriptor. There we should register Resteasy servlet that will get the requests and execute our web services. If you take a look at the code fragment – we register our Application in parameter javax.ws.rs.core.Application.

   <context-param>
      <param-name>javax.ws.rs.core.Application</param-name>
      <param-value>com.npenkov.testweb.WebServicesApp</param-value>
   </context-param>

   <context-param>
      <param-name>resteasy.servlet.mapping.prefix</param-name>
      <param-value>/re</param-value>
   </context-param>

   <listener>
      <listener-class>
         org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
      </listener-class>
   </listener>

   <servlet>
      <servlet-name>Resteasy</servlet-name>
      <servlet-class>
         org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
      </servlet-class>
   </servlet>

   <servlet-mapping>
      <servlet-name>Resteasy</servlet-name>
      <url-pattern>/re/*</url-pattern>
   </servlet-mapping>

Ready to start the server and deploy out web application. Right click on testweb in Package Explorer and right-click there. Then select “Run as” -> “Run on server”. Finish the process.

Wait for Geronimo to boot – you will see lots of messages in “Console” view in the bottom.
When it is ready – we can test our small web service. Open your browser and type the following url:
http://localhost:8080/testweb/re/first/tellMe

  • Usually default port for Jetty (web server) is set to 8080.
  • In the URL first we have our server and port.
  • Then is the webApplication name.
  • Then the mapping context that we specified in web.xml
  • the last two tokens are our service (“first”) and method (“tellMe”) – these are the words that we put as @Path in FirstServiceclass.

So we are ready now to start consuming web service from our web device. But first we have to write the client code in Android Application.

The Android Application

Start by creating new “Android Project”.

Make sure to select the runtime for the project. It might be that you have to consult here with Android Development documentation on how to create Virtual Device.

Continue with defining the main UI elements. We are not going to do something with lots of screens or functionallities – just one screen, with one input box for your WebService server IP address, one area that we will present responses there and finally – a button that will trigger WebService call. So starting with res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <LinearLayout
            android:id="@+id/linearLayout2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            <TextView
                android:id="@+id/lblIPAddress"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="IP Address" />
            <EditText
                android:id="@+id/editIPAddress"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1" >
                <requestFocus />
            </EditText>
        </LinearLayout>
        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0.42"
            android:text="TextView" />
        <Button
            android:id="@+id/btnCallService"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Call Service" />
    </LinearLayout>
</LinearLayout>

Now we should make sure to have access to google-gson – library that will help us move JSON formatted data into runtime objects. Right-click on Android project -> Properties. And set Java Build Path – add to libraries the jar file that you have extracted from google-gson archive.

Now some more about the WebService call classes and Interfaces. What I did – is to define one class called WebService. This class will be responsible for client <-> server communication. As of several releases – it is not allowed to make Asynchronic Network from main UI Thread – we should separate this logic, and executed in Async Task – means – extends android.os.AsyncTask. If you need more info on Threads in Android – there are great articles and demos on Android Development Web site.
Second major point in our simple architecture, is to define an interface for communication between UI and WebService call. We define the Interface

package com.npenkov.mobile;

public interface ICallbackHandler {
	public void response(String response);
}

In other words – our UI class will implement this interface and pass self instance to AsyncThread. When AsyncThread webservice class finishes his work – he will call implementation method response(String) of our UI class to notify about the result.
I have to admit here that some of the code for WebService Call – I have copied from Jose C Gomez’s Blog.

Now let us reveal the Mobile Magic.
First the declaration of the Activity (main execution View) – we are implementing here two Interfaces. One for listening of Click events (further we should tell to button to send events to this class) and one for listening for responses from Async Web Service call.

package com.npenkov.mobile;

import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class TestmobileActivity extends Activity
		implements OnClickListener, ICallbackHandler {
	private Button btnRunWebService;
	private TextView txtField;
	private TextView txtServerIP;
	private AlertDialog.Builder builder;

The onCreate method is executed in the begging of the Activity execution. There we obtain instances to UI objects from the view. Set that Activity will be the class for listening to Button click events.

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	builder = new AlertDialog.Builder(this);

	btnRunWebService = (Button) findViewById(R.id.btnCallService);
	txtField = (TextView) findViewById(R.id.textView);
	txtServerIP = (TextView) findViewById(R.id.editIPAddress);

	btnRunWebService.setOnClickListener(this);
}

Next – what should happen when the button is clicked – show confirmation dialog box and start the web service call:

public void onClick(View v) {
	builder.setMessage("Run REST request?").setCancelable(false)
			.setNegativeButton("OK", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					callWebService();
				}
			});
	AlertDialog alert = builder.create();
	alert.show();
}

And at the end – the Web Service call and response methods. When we call the service – we will take the IP address from the field that we defined. When we receive a response – a MsgObj – we will deserialize it using Gson and put the message text in the text field on the screen.

private void callWebService() {
	Map<String, String> params = new HashMap<String, String>();
	String serverIP = txtServerIP.getText().toString();
	WebService webService = new WebService(
			"http://"+ serverIP+":8080/testweb/re/first/",
			"tellMe", params, this, WebService.GET_METHOD);
	webService.execute();
}

@Override
public void response(String response) {
	Log.i("callMethod", "response");
	try {
		MsgObj msg = new Gson().fromJson(response, MsgObj.class);
		txtField.setText(msg.getMsgText());
	} catch (Exception e) {
		Log.d("Error: ", "Processing of " + response );
		if (e != null && e.getMessage() != null) Log.d("Error: ", e.getMessage() );
		else if (e != null) Log.d("Error: ", e.toString());
		else Log.d("Error: ", "Null Exception");
	}
}

At last we should enable our application to call web services on Internet. For almost all resource like operations, you should inform Android OS that you request this permission. If not – you will not have access to these services. So open your AndroidManifest.xml and add the following line


	<uses-permission android:name="android.permission.INTERNET"></uses-permission>

We are ready to test our application. Make sure Geronimo is running. Right click on testmobile project and execute it (“Run As” -> “Android Application”).

Obtain your IP address by executing command

ipconfig

if you are on Windows machine. And

ifconfig

if running MacOS or some UX type of OS.

Write down the address and push the button on your Android Emulator:

When you confirm this message box – you should see the message text from Web Service into text field that we defined on the screen:

Here you can download source code for Android application.
And here you can download source code for WebService application.

Enjoy~

How to quickly view your mobile number on iPhone

Recently I have changed my mobile number. I did not memorize it yet (learning to keep only indexes to information where it could be found – makes me forget numbers, names etc). So when you quickly try to view your number (for writing in form or giving to a friend) the easiest way is to
1) Go to home screen
2) Click on Phone
3) Navigate to Contacts search top area (taping on top bar) – and there you go

Usually this is done via 2 clicks (2, 3) when you keep your phone on Home screen.

Enjoy~

Quit MacOS Mail.app safely

It is very unlikely, but Mail.app that comes with MacOS is sometimes very buggy. Often it does not quit safely, and you have to kill it using Activity Monitor. It is especially annoying when it prevents computer from Shutdown. There is one trick, that at least for me – works every time. Before you quit the Mail.app – turn all accounts offline:

Wait until all accounts move to offline mode (Flash sign at the end of account) and quit Mail.app.

Next time when you start Mail, you should put accounts to online mode, by pressing Shift+Cmd+N (Get New Mail).

Obviously there is some asynchronous function in the application, that refreshes the content of your mail accounts, running in background and prevents application to quit. (for me this came with MacOS Lion release – before I had never experienced such behavior).

Running ABAP queries with dynamic WHERE clause – UPDATED

Here comes a short and simple example for ABAP Programming. Suppose you want to make some more flexible function module for searching data in database table, that depending on parameters that are passed (can be optional), forms the WHERE clause of select statement. In ABAP this is pretty straight forward:

FUNCTION zsfli_sflight_getlist.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(P_CARRID) TYPE ZSFLIGHT-CARRID OPTIONAL
*" VALUE(P_CONNID) TYPE ZSFLIGHT-CONNID OPTIONAL
*" VALUE(P_FLDATE) TYPE ZSFLIGHT-FLDATE OPTIONAL
*" TABLES
*" FLIGHT_DATA STRUCTURE ZSFLIGHT
*" RETURN STRUCTURE BAPIRET2
*"----------------------------------------------------------------------
  DATA l_where(100) OCCURS 0 WITH HEADER LINE.

  IF p_carrid IS NOT INITIAL.
    APPEND 'carrid = p_carrid' TO l_where.
  ENDIF.
  IF p_connid IS NOT INITIAL.
    IF l_where IS INITIAL.
      APPEND ' and ' TO l_where.
    ENDIF.
    APPEND 'connid = p_connid' TO l_where.
  ENDIF.
  IF p_fldate IS NOT INITIAL.
    IF l_where IS INITIAL.
      APPEND ' and ' TO l_where.
    ENDIF.
    APPEND 'fldate = p_fldate' TO l_where.
  ENDIF.

  SELECT * FROM sflight INTO CORRESPONDING FIELDS OF TABLE flight_data
  WHERE (l_where).

ENDFUNCTION.

In this way you can call function zsfli_sflight_getlist only with parameter p_fldate set, the select will filter and return all records for desired date.
Enjoy!

UPDATE: I have added additional check for checking if there are already added WHERE conditions, so that we can combine several conditions at once:

IF l_where IS INITIAL.
  APPEND ' and ' TO l_where.
ENDIF.

Get Ruby on Rails working on Ubuntu 11.10

A long time I have not been using Ruby On Rails. I have decided to give it a try again, so started by installing on Ubuntu 11.10 in VirtualBox. From what I remember – I have never happened before having issue with RoR working out of the box. Unfortunately this was not the case this time. Everything started with something really new to me:

Invalid gemspec in [/var/lib/gems/1.8/specifications/json-1.6.1.gemspec]: invalid date format in specification: "2011-09-18 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/json-1.6.1.gemspec]: invalid date format in specification: "2011-09-18 00:00:00.000000000Z"
Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z"

At the beginning I have tried to solve it in several ways – by installing ruby from APT sources via

sudo apt-get install rails

or just by installing rails from gems:

sudo gem install rails

Both re-installation and methods did not worked.
So I have to dig deeper.
After a lot of searching in google I found a simple solution. Obviously gemspecs have some different date formats that don’t validate. So if you have such a message, just run the following command:

sudo sed -i 's/ 00:00:00.000000000Z//' /var/lib/gems/1.8/specifications/*

This will fix the message. As soon as you install some new gem and you have this message – just run the script again.

Next it came the problem with SQLIte3:

Building native extensions. This could take a while...
ERROR: Error installing sqlite3-ruby:
ERROR: Failed to build gem native extension.

/usr/bin/ruby1.8 extconf.rb
checking for sqlite3.h... no
sqlite3.h is missing. Try 'port install sqlite3 +universal'
or 'yum install sqlite3-devel' and check your shared library search path (the
location where your sqlite3 shared library is located).
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.

This is solved by installing the development package of SQLite Ruby:

sudo apt-get install libsqlite3-dev

And at the end it came the problem with missing ExecJS engine:


/var/lib/gems/1.8/gems/execjs-1.2.9/lib/execjs/runtimes.rb:47:in `autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
from /var/lib/gems/1.8/gems/execjs-1.2.9/lib/execjs.rb:5
from /home/npenkov/Projects/MyMeetingMinutes/config/application.rb:5:in `require'
from /home/npenkov/Projects/MyMeetingMinutes/config/application.rb:5
from /var/lib/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:52:in `require'
from /var/lib/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:52
from /var/lib/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:49:in `tap'
from /var/lib/gems/1.8/gems/railties-3.1.1/lib/rails/commands.rb:49
from script/rails:6:in `require'
from script/rails:6

This I solved by downloading JavaScript engine from the URL mentioned (in my case Google V8) and putting on require in config/boot.rb

sudo gem install execjs
sudo gem install therubyracer

And adjust your applicaiton’s config/boot.rb:

require 'rubygems'
require 'execjs'
require 'v8'

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)

require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])

After all these fixes, everything ran smooth.
I am sure there could be more elegant way to fix all these issues, so feel free to propose solutions.
Enjoy!

Using development mode in SAP CRM 7.0 Web UI schemes

If you are going to customize or develop functionalities in SAP CRM 7.0 system, and you want to have access to different Web UI Roles, for sure you will want to choose them at least at logon. So, there is un easy solution for this – set user parameter CRM_UI_PROFILE to *. If you don’t know how to do this: start transition SU2 and create parameter as mentioned. After this you can start SAP CRM Web UI with transaction CRM_UI. After logon you will have un option to select your profile.

Set CRM User parameter for choosing WebUI Profiles

Enjoy~

Removing “.picasaoriginals” on uX system

Often I am facing one and the same issue – deleting backup folder of Picasa. There are usually lots of rotated images or movies. So usually this is the first place to search for free space.
Here is one very short way to delete these subdirectories:

cd ~/Pictures
find . -iname '.picasaoriginals' -exec rm -rf '{}' \;

This will remove all subdirectories from your “Pictures” folder that have name .picasaoriginals.

Enjoy~

←Older