Thursday, July 11, 2013

Push Notification Services with Android, GCM and Google App Engine (Part 3)

 

 

Introduction

As the last piece of the 3-piece architecture is implementation of the Android application which will be able to register and receive notification messages from GCM.

The complete Android application can be downloaded from here.

The sending of the notification is done in following order:

1. Google App engine – submit a message

2. Android application receives a notification 3. Android notification tray preview
Send 01 Screenshot_2013-07-11-18-46-07 Screenshot_2013-07-11-18-46-28

 

Implementation

The first part of Android application would be the communication to backend server that we developed before by using Google App Engine. This communication is done in asynchronous way and for this reason  AsyncTask class has been extended. GAEClient is in charge of handling HTTP requests. There is only single method implementation (storeRegistrationId) that is called once the device token is received and needs to be stored on the server.

public class GAEClient extends AsyncTask<Object, Void, String> {
// TODO: Change URL to Google App Engine application URL
private static final String URL = "http://<APP_NAME>.appspot.com/";
private static final String POST_ID_PARAM = "txtRegId";
private static final String POST_MSG_PARAM = "txtInput";
private String res;

@Override
// Checks HTTP page requests
protected String doInBackground(Object... objects) {
String action = (String)objects[0];
if(action.contains("storeid"))
{
String param = (String) objects[1];
return storeRegistrationId(param);
}else{
return null;
}
}

// Stores device token on the backend server
public String storeRegistrationId(String id){
String result = null;
try{
DefaultHttpClient client = new DefaultHttpClient();
HttpPost request = new HttpPost(URL+"storeid");
request.setHeader("Content-type", "application/x-www-form-urlencoded");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair(POST_ID_PARAM, id));
request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(request);
result = String.valueOf(response.getStatusLine().getStatusCode());
return result;
}catch(Exception e){
e.printStackTrace();
return "400";
}
}

@Override
protected void onPostExecute(String result) {
res = result;
}
}

 


The second part is GCMIntentService. This class is in charge of receiving a notification from the GCM and dispatching its message via broadcast to all Activities that will receive this message if they have broadcast listener implemented. In this simple demo, with single activity, only MainActivity will receive a message.


public class GCMIntentService extends GCMBaseIntentService {

@Override
protected void onMessage(Context context, Intent intent) {
String message = intent.getStringExtra("message");
if(message!=null){
Intent i = new Intent();
i.setAction("GCM_RECEIVED_ACTION");
i.putExtra("gcm", message);
context.sendBroadcast(i);
}
}

@Override
protected boolean onRecoverableError(Context context, String errorId) {
return super.onRecoverableError(context, errorId); //To change body of overridden methods use File | Settings | File Templates.
}

@Override
protected void onError(Context context, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}

@Override
protected void onRegistered(Context context, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}

@Override
protected void onUnregistered(Context context, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}
}

 


Once the Activity receives a message, the following step is to preview a message. They are few ways to display a notification, but the most common way is to use notification drawer (i.e. notification tray). NotificationDrawerMng builds notification for notification drawer preview.


public class NotificationDrawerMng{

public static Notification createNotification(Context context, String title, String message) {
// Prepare intent for notification display in
// the notification tray
Intent intent = new Intent();
intent.putExtra("message",message);
intent.putExtra("title",title);
int requestID = (int) System.currentTimeMillis();
PendingIntent pIntent = PendingIntent.getActivity(context, requestID, intent, 0);

// Build notification for tray display
Notification notification = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pIntent)
.build();
return notification;
}
}

 


In the broadcast listener, in the MainActivity, notification will be actually set inside the notification tray.


BroadcastReceiver gcmReceiver = new BroadcastReceiver() {
// Broadcast listener that receives a dispatched notification previously received
// from GCMIntentService
@Override
public void onReceive(Context context, Intent intent) {
broadcastMessage = intent.getExtras().getString("gcm");

if (broadcastMessage != null) {
Toast.makeText(getApplicationContext(), broadcastMessage, Toast.LENGTH_LONG).show();
Notification notification = NotificationDrawerMng.createNotification(getApplicationContext(), "GCMAndroidDemo", broadcastMessage);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

notification.flags = notification.flags | Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}
}
};

The last step is to add additional permissions in AndroidManifest for using GCM. Although we are using GCM don’t get confused since C2DM remained a configuration tag.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gcmdemo.GCMAndroidDemo"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="14"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<permission android:name="com.gcmdemo.GCMAndroidDemo.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.gcmdemo.GCMAndroidDemo.permission.C2D_MESSAGE" />
<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name="MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.gcmdemo.GCMAndroidDemo" />
</intent-filter>
</receiver>
<service android:name="com.gcmdemo.GCMIntentService" />
</application>
</manifest>

Wednesday, July 3, 2013

Push Notification Services with Android, GCM and Google App Engine (Part 1)

 

 

Introduction

In this blog I’ll demonstrate a solution for implementing push notification services for Android applications. It will leverage on the existing technologies that Google provides for the developers: Android platform, Google Cloud Messaging (GCM) and Google App Engine.

As you are probably already familiar, GCM is push notification service for Android platform that delivers notifications to your phone. Notifications are commonly used for notifying user about installed application updates or important status updates, for example, the Twitter application that notifies you about re-tweets. It is important to mention that push notification services (PNS) should be used with precaution since there are intended only to notify user about crucial things at the current moment. For example, if a user bids on an auction on the eBay, he/she should be notified if someone places bigger bid. Also, notifications should not be used if the messages will come too frequently. Too frequent notifications will annoy user and he/she will probably uninstall your app. PNSs are also not intended for delivering any confidential content since they don’t support encryption and they should not be used for these purposes. Instead, make sure you meet requirements as frequency, importance and sending it in a relevant time.

Architectural overview

First let’s get familiar with GCM, in order to better understand how our solutions will look like in the very end.
GCM system consists of three components:

  • Client (Android application) 
  • Backend server (Google App Engine backend)
  • GCM service

GCM provides us services for sending notifications to the Android smart phones. These notifications are messages that are constructed and sent to GCM by backend server who initiates notification sending (in Figure01 step a), i.e. backend server behaves as notification trigger. Backend server also stores all registration_ids of every subscriber (phone with installed application) and with these information server knows which group of subscribers it wants to target (in Figure01 step 3). Mobile app simply asks GCM for registration_id and connects to push service in order to receive notifications (in Figure01 step 1). It can also send registration_id delivered by GCM to the backend server (in Figure01 step 3).
For using GCM notification system several credentials need to be used:

  • sender_id - project number that uniquely identifies the project in Google Application Console,
  • application_id - identifies the application and it’s necessary to be used for receiving messages,
  • registration_id - identifies device with the installed app and it’s also necessary to be used for receiving messages. Device receives it from GCM service during connection process.
  • sender_auth_token - or API_KEY that is used on a server side in order to use GCM services
  • google_user_account - for Android versions lower than 4.0, Google account needs to be used.

GCM

Figure01 – GCM notification cycle

The complete process of notification sending can be explained with the following steps (see Figure01):

  • enabling GCM:
    1. (1) device is sending a request to the GCM. The request contains sender_id and app_id.
    2. (2) GCM sends response containing app_id and registration_id.
    3. (3) mobile app sends received registration_id to backend server, which stores the id
  • sending a message:
    1. (‘a’) backend server with defined API_KEY sends a message content with a set of registration_ids of device it wants to target
    2. (‘b’) GCM receives the message from server and broadcasts it to the devices
  • receiving a message (on a device)
    1. mobile app receives the notification, extracts it and processes data
    2. displays message content

Generating credentials

Now we’ll go through steps of how to generate mentioned credentials that we’ll later use in our implementation.

Step 01: Go to Google API Console web site and log in with your Gmail account.

Google Api Console

Figure02 – Google API Console start page

Step 02: Create project…

Step 03: Enter project name and continue

Step 04: In the left navigation menu go to Services and enable Google Cloud Messaging for Android

GCMEnable

Figure03 – Turn on GCM for Android

Step 05: In the same menu go to API Access. Now you need to create a server key. Click on Create New Server Key… and for this case leave IPs field empty and follow with create (no IP address needs to be specified if you want to be in public domain).

Step 06: In the same menu go to Overview.

So far we generated following credentials:

  • sender_id: in the Overview you can see Project Number and that is your sender_id (will be used in Android application)
  • application_id: as explained before will be received from the GCM when the mobile connects to the GCM
  • registration_id: as explained before will be received from the GCM when the mobile connects to the GCM
  • sender_auth_token: in the API Access you can see under Key for server apps (with IP locking) the API key which is your sender authentication token (will be used in Google App Engine web application)
  • google_user_account: is not necessary since in this tutorial will develop Android 4.0 application

Now we are ready to implement our notification system. Follow this next blog.

Tuesday, March 5, 2013

Build cross platform mobile application with jQ.Mobi and PhoneGap

 

Introduction

In this blog post we’ll learn how to build a mobile application for multiple platforms by using JavaScript library called jQ.Mobi and PhoneGap cloud build service.

In the first part, there will be shown steps of building a “Hello, world” mobile application in HTML5/JavaScript/CSS3. This will be done by using free jQ.Mobi library that allow us to build application with native look&feel of the specific platforms in very easy way.

The second part will describe how to use PhoneGap cloud build service which allow us to build our previous “Hello, world” project for multiple platforms. What this service is providing, is it will build executable install files for each of the platforms: iOS, Android, WP, Blackberry, HP and Symbian.

Part 01 – “Hello, world”

Firstly, download jQ.Mobi library from GitHub link just by clicking ZIP button. After download finishes, extract the archive.

Now create a separate folder for your new “Hello, world” project. Inside the directory create another directory named “www”. Copy plugins, kitchensink and ui folders from extracted jQ.Mobi folder. Also, copy jq.mobi.js and jq.mobi.min.js. In the “www” folder, create index.html empty file. Now the current folder structure should look like this:

directory structure

Picture 01 – Project directory structure

Now we’ll edit our index.html file with the following code:

<!DOCTYPE html>
<!--HTML5 doctype-->
<html>

<head>
<title>jqUi Starter</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes" />

<link rel="stylesheet" type="text/css" href="kitchensink/icons.css" />
<link rel="stylesheet" type="text/css" href="kitchensink/jq.ui.css" title="volcano"/>

<script type="text/javascript" charset="utf-8" src="ui/jq.ui.min.js"></script>

<script>
if (!((window.DocumentTouch && document instanceof DocumentTouch) || 'ontouchstart' in window)) {
$.os.android = true; //let's make it run like an android device
}

</script>
<script type="text/javascript">

var webRoot = "./";
$.ui.backButtonText = "Back";// We override the back button text to always say "Back"
</script>
</head>

<body>
<div id="jQUi"> <!-- this is the main container div. This way, you can have only part of your app use jqUi -->
<!-- this is the header div at the top -->
<div id="header">

</div>
<div id="content">
<!-- here is where you can add your panels -->
<div title='Welcome' id="main" class="panel">This is a "Hello, world" sample.</div>
<div title="Targeting platforms" id="jqmweb" class="panel" data-header="testheader">
<h2 class='expanded' onclick='showHide(this,"jqweb_info");'>Platforms</h2><p id='jqweb_info'>
We wish to support following platforms:</p>
<ul>
<li>iOS</li>
<li>Android</li>
<li>Windows Phone</li>
<li>Blackberry</li>
<li>HP</li>
<li>Symbian</li>
</ul>
<br/><br/>
</div>
</div>
<!-- bottom navbar. Add additional tabs here -->
<div id="navbar">
<div class="horzRule"></div>
<a href="#main" id='navbar_home' class='icon home'>home</a>
<a href="#jqmweb" id='navbar_target' class='icon target'>target</a>
</div>
</div>
</body>
</html>

 


In the head tag you can see we referenced JavaScript files and CSS from the jQ.Mobi library. There is additional initialization JavaScript that runs first time the app starts. In the body part there are two divs that are loaded depending on button click from the navigation bar (“navbar”). First div with id="main" is the main page, while other div with id="jqmweb" represents the second page with list of items.


TIP: If you want to use Visual Studio for easy project editing, simply go File>Open>Web Site and browse to your project folder.


Now you can test index.html page preview in browser. After you navigate with “home” and “target” buttons you should see slide animation.










mainpage


targetpage


Picture 02 – Main page


Picture 03 – Target page


Now when your “Hello, world” app is done, zip the entire folder to .zip archive.


Part 02 – PhoneGap build service


With your browser go to https://build.phonegap.com/. Login with your Adobe account or GitHub account. If you don’t have account you can go to the GitHub official web site and register for a free account. After you have been logged in:


1. Click on New App button.


phonegap-build01


2. Select Private tab, click Upload a .zip file, browse to your zip project archive and click Ready to build.


phonegap-build02


TIP: For a free use you can only upload 1 zip archive, but instead, you could use GitHub repository and build your application directly from there.


3. After your build is finished you can download executable files for these platforms:


PGBuildApp


TIP: For the iOS case you’ll first need to upload application certificate and build afterwards.

Monday, February 25, 2013

Android with WCF web services


Introduction

This post will briefly describe how to implement WCF web service client side in an Android application. For this purpose, simple “ToDo” Android application will be used for demonstration. The complete source code can be downloaded from here.
The easiest way to do this is by using WCF Rest services that will send information in JSON or XML format. If you would like to use SOAP base services, then you would need to use some 3rd party libraries for Android like kSOAP.

Implementing WCF web service

In this post, we’ll use Azure project approach to implement web service, but any other approach will serve the purpose also.
The first step is to create new Azure Cloud Service project. If you don’t have Azure SDK installed, you can download it from Azure web site. In .NET section you’ll find installs both for VS2012 and VS2010.
In Visual Studio, go File > New Project and under the Cloud category choose Windows Azure Cloud Service project. Fill in necessary data, hit Ok and afterwards select WCF Service Web Role.
NewAzureProj
Step 01: Select Azure project
AzureRoleStep 02: Select WCF Service Role
After you created your project, add a new WCF service or refactor default WCF service that has been generated within the project. Replace service interface with the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WCFServiceWebRole1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IToDoService" in both code and config file together.
    [ServiceContract]
    public interface IToDoService
    {
        [OperationContract]
        [WebInvoke(
            Method = "POST",
            UriTemplate = "AddToDoItem",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        void AddToDoItem(ToDoItem toDoItem);

        [OperationContract]
        [WebInvoke(
            Method = "GET",
            UriTemplate = "GetToDoItemsByDate?date={date}",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        List<ToDoItem> GetToDoItemsByDate(String date);

        [OperationContract]
        [WebGet(
            UriTemplate = "GetAllToDoItems",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        List<ToDoItem> GetAllToDoItems();
    }

    [DataContract]
    public class ToDoItem
    {
        [DataMember(Name = "description")]
        public String Description { get; set; }
        [DataMember(Name = "scheduleddate")]
        public DateTime ScheduledDate { get; set; }
    }
}

As you can see we have defined three methods:


  1. AddToDoItem – will be used for adding a new ToDo item. It will receive a ToDo item in JSON format (RequestFormat), through POST request.
  2. GetToDoItemsByDate – will be used to retrieve all ToDo items for specific date. Method receives date as an argument in JSON format, through GET request and retrieves list of ToDo items also in JSON format (ResponseFormat).
  3. GetAllToDoItems – will be used to retrieve all ToDo items. The list of items in JSON format will be in response body for GET request.

DataContract represents the ToDo item model and defines the model properties.

In the next step, we need to implement interface methods:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Text;

namespace WCFServiceWebRole1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ToDoService" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select ToDoService.svc or ToDoService.svc.cs at the Solution Explorer and start debugging.
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ToDoService : IToDoService
    {  
        public void AddToDoItem(ToDoItem toDoItem)
        {
            int id = 0;
            try
            {
                using (SqlConnection con = DBConnection.GetConnection())
                {
                    SqlCommand cmd = new SqlCommand("InsertToDo", con);
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    cmd.Parameters.Add(new SqlParameter("@ScheduledDate", toDoItem.ScheduledDate));
                    cmd.Parameters.Add(new SqlParameter("@Description", toDoItem.Description));
                    
                    con.Open();

                    SqlDataAdapter ad = new SqlDataAdapter(cmd);
                    DataSet ds = new DataSet();
                    ad.Fill(ds);
                    DataTable result = ds.Tables[0];
                    foreach (DataRow row in result.Rows)
                    {
                        id = Int16.Parse(row[0].ToString());
                    }
                    con.Close();
                }
                
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }

        public List<ToDoItem> GetAllToDoItems()
        {
            List<ToDoItem> items = new List<ToDoItem>();
            using (SqlConnection con = DBConnection.GetConnection())
            {
                SqlCommand cmd = new SqlCommand("GetAllToDoItems", con);
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                con.Open();

                SqlDataAdapter ad = new SqlDataAdapter(cmd);
                DataSet ds = new DataSet();
                ad.Fill(ds);
                DataTable result = ds.Tables[0];

                if (result == null)
                {
                    return null;
                }
                else
                {
                    foreach (DataRow row in result.Rows)
                    {
                        ToDoItem todo = new ToDoItem();
                        todo.ScheduledDate = DateTime.Parse(row[1].ToString());
                        todo.Description = row[2].ToString();

                        items.Add(todo);
                    }
                }
                con.Close();
            }

            return items;
        }

        public List<ToDoItem> GetToDoItemsByDate(String date)
        {
            List<ToDoItem> items = new List<ToDoItem>();
            try
            {
                using (SqlConnection con = DBConnection.GetConnection())
                {
                    SqlCommand cmd = new SqlCommand("GetToDoItemsByDate", con);
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    cmd.Parameters.Add(new SqlParameter("@ScheduledDate", date));
                    con.Open();

                    SqlDataAdapter ad = new SqlDataAdapter(cmd);
                    DataSet ds = new DataSet();
                    ad.Fill(ds);
                    DataTable result = ds.Tables[0];
                    if (result == null)
                    {
                        return null;
                    }
                    else
                    {
                        foreach (DataRow row in result.Rows)
                        {
                            ToDoItem todo = new ToDoItem();
                            todo.ScheduledDate = DateTime.Parse(row[1].ToString());
                            todo.Description = row[2].ToString();

                            items.Add(todo);
                        }
                    }
                    con.Close();
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }

            return items;
        }

    }
}

The concrete implementation contains only SQL stored procedure calls. With these stored procedures, data are stored in and retrieved from MSSQL database. Also, DBConnection class defines DB connection and connection string and it looks like this:



using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Web;

namespace WCFServiceWebRole1
{
    public class DBConnection
    {
        private static String connectionString = "user id=<USERNAME>;" +
                                      @"password=<PASSWORD>;server=<YOUR_HOST>\<MSSQLSERVER>;" +
                                       "Trusted_Connection=yes;" +
                                       "database=ToDoDB; " +
                                       "connection timeout=30";
        private static SqlConnection con = null;

        public static SqlConnection GetConnection()
        {
            con = new SqlConnection(connectionString);
            return con;
        }

        public static void CloseConnection()
        {
            if (con != null)
                con.Close();
        }

        public static void OpenConnection()
        {
            if (con != null)
                con.Open();
        }
    }
}

The last thing concerning WCF service implementation is configuration within WebConfig file in your project. Under <system.serviceModel>, in your config file, you’ll need to make the following changes:

  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="httpBehavior">
          <dataContractSerializer maxItemsInObjectGraph="10000000"/>
          <webHttp/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
    <services>
      <service name="WCFServiceWebRole1.ToDoService">
        <endpoint address="web" 
                  behaviorConfiguration="httpBehavior"
                  binding="webHttpBinding" 
                  contract="WCFServiceWebRole1.IToDoService" />
        <endpoint address="" 
                  binding="basicHttpBinding" 
                  contract="WCFServiceWebRole1.IToDoService" />
      </service>
    </services>
  </system.serviceModel>



Notice, that you’ll need to add <behavior name="httpBehavior"> and service endpoints under <services>. For purpose of demonstration, you can notice two endpoints with different bindings: basic and web. For current implementation, you can only use webHttpBinding, but in the case you have a legacy WCF service with different binding, you can simply add another endpoint for your new requirement and WCF service will continue to work with the previous and the new binding as well.

Implementing Android WCF client


In this section, it will be only presented the code for communication with previously implemented web service. For complete Android application you can refer to complete project from this link.

Since we are using Rest services the client can be implemented by using HttpRequests. The following code represents the implementation of client side in Android application for each web service’s method call:



package com.smallsoftlab.ToDoDemo.Services;

import android.os.AsyncTask;
import com.smallsoftlab.ToDoDemo.Model.ToDoItemModel;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONStringer;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created with IntelliJ IDEA.
 * User: Vladimir
 * Date: 2/20/13
 * Time: 2:00 PM
 * To change this template use File | Settings | File Templates.
 */
public class Services extends AsyncTask<Object, Void, String> {
    private static final String SVC_URL = "http://10.0.2.2:81/ToDoService.svc/web";

    @Override
    protected String doInBackground(Object... params) {
        String action = params[0].toString();
        if (action.contains("AddToDoItem")) {
            ToDoItemModel toDoItem = (ToDoItemModel) params[1];
            return addToDoItem(action, toDoItem);
        } else if (action.contains("GetToDoItemsByDate")) {
            Date date = (Date) params[1];
            return getToDoItemsByDate(action, date);
        } else if (action.contains("GetAllToDoItems")) {
            return getAllToDoItems(action);
        }
        return null;
    }

    public String addToDoItem(String action, ToDoItemModel toDoItem) {
        int statusCode = 400;
        try {
            // POST request to <service>/AddToDoItem
            // Adds new ToDoItem
            HttpPost request = new HttpPost(SVC_URL + action);
            request.setHeader("Accept", "application/json");
            request.setHeader("Content-type", "application/json");

            // Build JSON string
            JSONStringer item = new JSONStringer()
                    .object()
                    .key("toDoItem")
                    .object()
                    .key("description").value(toDoItem.getDescription())
                    .key("scheduleddate").value("/Date("+toDoItem.getScheduleDate().getTime()+")/")
                    .endObject()
                    .endObject();
            StringEntity entity = new StringEntity(item.toString());

            request.setEntity(entity);

            // Send request to WCF service
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpResponse response = httpClient.execute(request);

            statusCode = response.getStatusLine().getStatusCode();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return String.valueOf(statusCode);
    }

    public String getToDoItemsByDate(String action, Date date) {
        String result = "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // GET request to <service>/GetToDoItemsByDate
            // Gets a list of ToDoItems for specific date
            HttpGet request = new HttpGet(SVC_URL + action + "?date=" + sdf.format(date));
            request.setHeader("Accept", "application/json");
            request.setHeader("Content-type", "application/json");

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpResponse response = httpClient.execute(request);

            HttpEntity responseEntity = response.getEntity();

            // Read response data into buffer
            char[] buffer = new char[(int) responseEntity.getContentLength()];
            InputStream stream = responseEntity.getContent();
            InputStreamReader reader = new InputStreamReader(stream);
            reader.read(buffer);
            stream.close();

            result = new String(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public String getAllToDoItems(String action) {
        String result = "";
        try {
            // GET request to <service>/GetAllToDoItems
            // Gets all ToDoItems 
            HttpGet request = new HttpGet(SVC_URL + action);
            request.setHeader("Accept", "application/json");
            request.setHeader("Content-type", "application/json");

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpResponse response = httpClient.execute(request);

            HttpEntity responseEntity = response.getEntity();

            // Read response data into buffer
            char[] buffer = new char[(int) responseEntity.getContentLength()];
            InputStream stream = responseEntity.getContent();
            InputStreamReader reader = new InputStreamReader(stream);
            reader.read(buffer);
            stream.close();

            result = new String(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

NOTICE: You can see the service URL is directed to 10.0.2.2, and use this IP address since it is the address of the host that runs the WCF service. Do not use 127.0.0.1 since that would be the address of your Android phone or emulator that runs the application. Also, after you run your Azure project on the emulator, check the port number in your URL. Usually, it is 81, but if it is different you’ll need to change it to the right one.

For the newest versions of Android SDK you’ll need to use the AsyncTask class for any kind of connection to remote resource. After you extend this class you’ll override the doInBackground method that receives the array of arguments. This method will proxy your request to specific web service call.

The way you need to use Services class is like this:

    //Add ToDoItem
    public String addToDoItem(ToDoItemModel toDoItem) {
        String status = null;
        try {
            Services svc = new Services();
            status = svc.execute("/AddToDoItem", toDoItem).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return status;
    }

where status represents the return value of method. It can also be a JSON result for GetToDoItemsByDate and GetAllToDoItems call.

Do not use this:

status = svc.addToDoItem("/AddToDoItem", toDoItem);

Instead use execute() which calls doInBackground method from Services class.

Thursday, October 25, 2012

Clarifying Mediator pattern

 

 

Introduction

Mediator is design pattern that is primarily used to loose coupling between components in their communication. For instance, if each of components would communicate to each other directly, we could get a complex net of communication lines between these components. Instead of direct communication we are using mediator who will be intermediate component for inside communication between components.
Simple scenario for mediator role would be to gather messages from each component (component is in some books referred as Colleague), and than mediator would broadcast that message to all other components.
In the next image we can see UML class diagram showing us dependencies between classes in implementation of Mediator pattern. Mediator and Component can be either abstract classes or interfaces, depending of the specific implementation.

 
ClassDiagram
UML class diagram representing Mediator pattern
 
Now, there is a question, since mediator using broadcast, how each of components would know that the message is intended just for her. Well, in most cases message contains a key value that would be known to the receiver and sender, and it will be used to determine the originator and receiver of the message. There is also possibility to send sender and recipient information within the message. So, when the message is received by some component, component can determine if the message is intended for her or some other component, in that way message can be processed or ignored.
From the security side, this is not very safe way to distribute all messages as a broadcast, but if implementation is not restricted with security rules (for example, UI classes) than it can have a good purpose to decouple communication between components.

Implementation

In this blog I’ll demonstrate simple chat application written in Java. Application will contain three tabs (three components, i.e. Colleague), and each of the tabs will be able to communicate with other tabs over the Mediator. For the message representation I’ll implement Intent class which instances will be able to contain string messages. Of course, current implementation of Intent can be extended and used to wrap other object types in a message as well.

Mediator demo app
Screenshot of the Mediator demo application

Current implementation of demo project is demonstrated in the next picture:

NewDiagram
UML class diagram representing implementation of Mediator pattern
 

Source code from demo project can be downloaded from here.


Now, let’s take a look at the code.
This is simple Mediator interface that will be implemented in the Mediator class.

package com.testmediator;
public interface IMediator {
  public void addComponent(IComponent _component);
  public void send(Intent _message, IComponent _sender);
}

Class Mediator implements previous interface with two methods. Method addComponent is used for registering components, since the Mediator needs to know all actors of communication. Second method, send, simply broadcasts message to all of the components, except sender component.
package com.testmediator;
import java.util.ArrayList;
public class Mediator implements IMediator{
  private ArrayList<IComponent> components = new ArrayList<IComponent>();
  
  @Override
  public void addComponent(IComponent _component) {
    components.add(_component);
  }
  @Override
  public void send(Intent _message, IComponent _sender) {
    for(IComponent component : components){
      if(!component.equals(_sender)){
        component.receive(_message);
      }
    }
  }
}

In the next code preview you can see Component interface that will be implemented in Component classes.
package com.testmediator;
public interface IComponent {
  public void receive(Intent _message);
  public void send(Intent _message, IComponent _sender);
  public IMediator getMediator();
}

As you can see in the Component implementation, each Component contains the reference to the same Mediator that is set up in the constructor. Other important methods are send and receive which implements sending message via Mediator instance and receiving message from Mediator broadcast, respectively. On the click of the send button message will be send to another component depending of selected recipient from the combo box.
package com.testmediator;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class ComponentOne extends WindowAdapter implements IComponent, ActionListener{
  private IMediator m_mediator = null;
  private JPanel m_panel = null;
  private JComboBox<String> m_tabSelect = null;
  private JLabel m_label = null;
  private JTextField m_text = null;
  private JButton m_button = null;
  private JLabel m_receivedMsg = null;
  private Intent m_message = null;
  
  public ComponentOne(IMediator mediator){
    m_mediator = mediator;
    initGui();
  }
  
  @Override
  public void receive(Intent _message) {
    m_message = _message;
    if(m_message.getStringMsg("ToTab01")!=""){
      m_receivedMsg.setText(m_receivedMsg.getText() + " - " + m_message.getStringMsg("ToTab01"));
    }
    m_panel.repaint();
  }
  @Override
  public void send(Intent _message, IComponent _sender) {
    m_mediator.send(_message, this);
  }
  @Override
  public IMediator getMediator() {
    return m_mediator;
  }
  
  private void initGui(){
    m_panel = new JPanel();
    
    m_tabSelect = new JComboBox<String>();
    m_tabSelect.addItem("tab02");
    m_tabSelect.addItem("tab03");
    m_label = new JLabel("Tab01, enter the message: ");
    m_text = new JTextField(20);
    m_button = new JButton("Send");
    m_button.addActionListener(this);
    m_receivedMsg = new JLabel("Received: ");
    
    m_panel.add(m_tabSelect);
    m_panel.add(m_label);
    m_panel.add(m_text);
    m_panel.add(m_button);
    m_panel.add(m_receivedMsg);
  }
  
  public JPanel getPanel(){
    return m_panel;
  }
  
  public Intent getMessage(){
    return m_message;
  }
  @Override
  public void actionPerformed(ActionEvent _event) {
    Object source = _event.getSource();
    if(source.equals(m_button)){
      Intent intent = new Intent();
      if(m_tabSelect.getSelectedItem() == "tab02"){
        intent.putStringMsg("ToTab02", m_text.getText());
      }else if(m_tabSelect.getSelectedItem() == "tab03"){
        intent.putStringMsg("ToTab03", m_text.getText());
      }
      send(intent,this);
    }
  }
}

Simple Intent class represents wrapper for all messages. As you can see for now it contains only methods for putting string message and reading the same message. This class can be extended to wrap all other kinds of objects.
package com.testmediator;
public class Intent {
  String m_stringMsgKey;
  String m_stringMsg = "";
  public void putStringMsg(String _key, String _value){
    m_stringMsgKey = _key;
    m_stringMsg = _value;
  }
  
  public String getStringMsg(String _messageKey){
    if(_messageKey == m_stringMsgKey){
      return m_stringMsg;
    }
    else{
      return "";
    }
  }
}

Other classes from project are excluded from code preview since primary role of this blog was to present Mediator pattern. In a context of the project it is basically a simple desktop app developed using swing library.


Conclusion


Mediator pattern is pretty common to meet in a different solutions. For instance, Android platform is using very similar principle regarding communication between Activities using Intent objects as messages that will be broadcasted to all Activity instances in the app. This way complex peer-to-peer communication is replaced by the Mediator who is in charge of distributing messages, providing loose coupling between components which is in the almost all cases very good practice.