the Flagship blog & community for App Developers with main focus on Samsung's bada and cross-platform technologies
Bada Tutorials

Communication improved using C++ templates

Communication in Bada is made simple by a few API features such as the SendUserEvent/OnUserEventReceivedN duo. This couple of function is present in the 3 base elements of a Bada program: Form, Application and Thread.
Using those two functions, you can send any messages to your Thread, Forms and Application without directly dealing with thread synchronisation, signals and all those horrible stuffs. Very nice feature, at least from a low-level C developer point of view ;)

However those are not very practical to use since they only accept a pointer to a list as parameter. Let’s see how we can improve their usability and learn C++ templates on the way.
We could have make simple helper functions that first create the list from some typical parameter configuration (a String, an int…) and then pass this list to the SendUserEvent function. But we are lazy (aren’t we all?) so we just want an all-in-one function to be called.

Instead we will use these helper functions in combination with functions that takes usual parameters used for communication and a pointer to an object of type T. This object can be a Form, a Thread or the Application.
For example for a single String parameter we have :

static result SendEvent(T *targetObject, RequestId requestId, const String &single_parameter);

This static method create the ArrayList from the parameter and pass it to the SendUserEvent of the targeted object.
However in C++ we cannot determine the type of T at runtime. But we can use templates instead! The correct way of doing this is:

template <class T>
result SendEvent<T>(T *target, RequestId requestId, const Osp::Base::String &single_parameter)

So we can say at compilation if T is either a Form or a Thread or an Application, for example we can call in our code:

Form *myForm;
RequestId myRequestId;
String myParameter;
SendEvent<Form>(myForm, myRequestId, myStringParameter);

to send an event to our form. Here SendEvent<Form> is a template method using Form as the template parameter ( i.e. now T == Form).

We could have stopped here but what if I don’t want to call a static function but directly call our communications methods on our Form ? Instead of template methods, we will use a template class which will be inherited by the target objects of our application (remember: Forms, Threads, Application).
I will call this class MessageRelayT as this tutorial is strongly inspired by the work of our master wit in Form Managment Part 3.

The signature of our template class is :

template <class T>
class  MessageRelayT {
//...
}; 

Here is the UML diagram of the idea (only Form and Thread are shown for clarity’s sake, but same goes for Application):
MessageRelay UML schema

The MessageRelay class contains helpers methods to build array lists from usual parameters and some other bonuses.
The MessageRelayT class contains the SendEvent methods to be called on the objects in order to communicate. Those methods are wrappers that call the static methods we previously seen, passing “this” as the target parameter, for example :

result SendEvent(RequestId requestId, int single_parameter)
{
return SendEvent(dynamic_cast<T*>(this), requestId, single_parameter); //the static method seen in the first part of this tutorial
}

Pay attention to the use of dynamic_cast here as it’s a little tricky.  MessageRelayT is inherited by MyForm which also inherit from Form, so in MyForm “this” is a pointer to both a Form object and a MessageRelayT object. That’s why we should use dynamic_cast which is able to make the difference at runtime, where a standard C cast (i.e. (T*)this ) is not.

How do we use all this stuff at the end ? In our application we have a Form myForm which inherits both from MessageRelayT<Form> and from Osp::Ui::Control::Form.

class MyForm :
public Osp::Ui::Controls::Form,
public MessageRelayT<Form>

To send events to myForm in our application, now we can just call:

RequestId myRequest;
myForm.SendEvent(myRequest, "Hello, Form !"); // send a String

or

RequestId myRequest;
myForm.SendEvent(myRequest, 42); // send an int

Nice !

Some Java programmers at this point should say: “hey wait! you are inheriting from more than one base class! this is not possible!”, and some C++ programmers will also say: “this is evil!!”. In fact, in C++ we can do it, so why not using it ? At least as long as it is with simple little helper class like here an not with too complex structures where multiple inheritance could lead to… well… evil ;)

Here is the complete code, plus some bells and whistles :

class MessageRelay{
public:
 MessageRelay() {}
 virtual ~MessageRelay() {}

//Build an array list from usual parameters
 static Osp::Base::Collection::ArrayList* GetArgumentList(int single_parameter);
 static Osp::Base::Collection::ArrayList* GetArgumentList(const Osp::Base::String &single_parameter);
 static Osp::Base::Collection::ArrayList* GetArgumentList(const Osp::Base::String &first_parameter, const Osp::Base::String &second_parameter);
 static Osp::Base::Collection::ArrayList* GetArgumentList(const Osp::Base::Object *single_parameter);

//Static methods to send events to the application using Application::GetInstance()
 static result SendEventToApp(RequestId requestId, Osp::Base::Collection::IList *pArgs);
 static result SendEventToApp(RequestId requestId, int single_parameter);
 static result SendEventToApp(RequestId requestId, const Osp::Base::String &single_parameter);
 static result SendEventToApp(RequestId requestId, const Osp::Base::String &first_parameter, const Osp::Base::String &second_parameter);
 static result SendEventToApp(RequestId requestId, Osp::Base::Object *single_parameter);
};

/** This template class is indented to be inherited and templated ONLY by class having a member function defined as:
 *     SendUserEvent  ( RequestId  requestId, const Osp::Base::Collection::IList *  pArgs)
 *    In Bada API v1.0 :
 *         Osp::App::Application
 *         Osp::Base::Runtime::Thread
 *         Osp::Ui::Controls::Form
 */
template <class T>
class MessageRelayT
 : public MessageRelay{
private:
public:
 MessageRelayT() {}
 virtual ~MessageRelayT() {}
 virtual result SendEvent(RequestId requestId, Osp::Base::Collection::IList *pArgs){ return SendEvent(dynamic_cast<T*>(this), requestId, pArgs); }
 virtual result SendEvent(RequestId requestId, int single_parameter) { return SendEvent(dynamic_cast<T*>(this), requestId, single_parameter); }
 virtual result SendEvent(RequestId requestId, const Osp::Base::String &amp;single_parameter) { return SendEvent(dynamic_cast<T*>(this), requestId, single_parameter); }
 virtual result SendEvent(RequestId requestId, const Osp::Base::String &first_parameter, const Osp::Base::String &second_parameter) { return SendEvent(dynamic_cast<T*>(this), requestId, first_parameter, second_parameter); }

 //The object must be allocated on the heap and must not be deleted after a successful call, but must be deallocated in case of error
 virtual result SendEvent(RequestId requestId, const Osp::Base::Object *single_parameter) { return SendEvent(dynamic_cast<T*>(this), requestId, single_parameter);}
 static result SendEvent(T *target, RequestId requestId, Osp::Base::Collection::IList *pArgs);
 static result SendEvent(T *target, RequestId requestId, int single_parameter);
 static result SendEvent(T *target, RequestId requestId, const Osp::Base::String &single_parameter);
 static result SendEvent(T *target, RequestId requestId, const Osp::Base::String &first_parameter, const Osp::Base::String &second_parameter);
//The object must be allocated on the heap and must not be deleted after a successful call, but must be deallocated in case of error
 static result SendEvent(T *target, RequestId requestId, const Osp::Base::Object *single_parameter);
};

template <class T>
result MessageRelayT<T>::SendEvent(T *target, RequestId requestId, Osp::Base::Collection::IList *pArgs)
{
 result r = E_SUCCESS;
 TryReturn(target!=null, E_FAILURE, "Target is null");
 (target)->SendUserEvent(requestId, pArgs);
 return r
}

template <class t>
result MessageRelayT<T>::SendEvent(T *target, RequestId requestId, int single_parameter)
{
 result r = E_SUCCESS;
 TryReturn(target!=null, E_FAILURE, "Target is null");
 Osp::Base::Collection::ArrayList *list = null;
 list = GetArgumentList(single_parameter);
 TryReturn(list!=null, E_FAILURE, "Cannot get argument list");
 target->SendUserEvent(requestId, list);
 return r;
}

template <class T>
result MessageRelayT<T>::SendEvent(T *target, RequestId requestId, const Osp::Base::String &single_parameter)
{
 result r = E_SUCCESS;
 TryReturn(target!=null, E_FAILURE, "Target is null");
 Osp::Base::Collection::ArrayList *list = null;
 list = GetArgumentList(single_parameter);
 TryReturn(list!=null,E_FAILURE, "Cannot get argument list");
 (target)->SendUserEvent(requestId, list);
 return r;
}

template <class T>
result MessageRelayT<T>::SendEvent(T *target, RequestId requestId, const Osp::Base::String &first_parameter, const Osp::Base::String &second_parameter)
{
 result r = E_SUCCESS;
 TryReturn(target!=null, E_FAILURE, "Target is null");
 Osp::Base::Collection::ArrayList *list = null;
 list = GetArgumentList(first_parameter, second_parameter);
 TryReturn(list!=null,E_FAILURE, "Cannot get argument list");
 (target)->SendUserEvent(requestId, list);
 return r;
}

template <class T>
result MessageRelayT<T>::SendEvent(T *target, RequestId requestId, const Osp::Base::Object *single_parameter)
{
 result r = E_SUCCESS;
 TryReturn(target!=null, E_FAILURE, "Target is null");
 Osp::Base::Collection::ArrayList *list = null;
 list = GetArgumentList(single_parameter);
 TryReturn(list!=null,E_FAILURE, "Cannot get argument list");
 (target)->SendUserEvent(requestId, list);
 return r;
}
#include "MessageRelay.h"
using namespace Osp::App;
using namespace Osp::Base;
using namespace Osp::Base::Collection;

result
MessageRelay::SendEventToApp(RequestId requestId, IList *pArgs)
{
 Application *appinstance = Application::GetInstance();
 return MessageRelayT<Application>::SendEvent(appinstance, requestId, pArgs);
}

result
MessageRelay::SendEventToApp(RequestId requestId, int single_parameter)
{
 Application *appinstance = Application::GetInstance();
 return MessageRelayT<Application>::SendEvent(appinstance, requestId, single_parameter);
}

result
MessageRelay::SendEventToApp(RequestId requestId, const String &single_parameter)
{
 Application *appinstance = Application::GetInstance();
 return MessageRelayT<Application>::SendEvent(appinstance, requestId, single_parameter);
}

result
MessageRelay::SendEventToApp(RequestId requestId, const String &first_parameter, const String &second_parameter)
{
 Application *appinstance = Application::GetInstance();
 return MessageRelayT<Application>::SendEvent(appinstance, requestId, first_parameter, second_parameter);
}

result
MessageRelay::SendEventToApp(RequestId requestId, Object *single_parameter)
{
 Application *appinstance = Application::GetInstance();
 return MessageRelayT<Application>::SendEvent(appinstance, requestId, single_parameter);
}

ArrayList*
MessageRelay::GetArgumentList(int single_parameter)
{
 result r = E_SUCCESS;
 ArrayList *list = null;
 Integer *arg1 = null;
 list = new  ArrayList;
 TryCatch(list!=null,, "Cannot instantiate argument list");
 arg1 = new Integer(single_parameter);
 TryCatch(arg1!=null,, "Cannot instantiate argument");
 r = list->Construct(1);
 TryCatch(!IsFailed(r),, "Cannot construct argument list");
 r = list->Add(*arg1);
 TryCatch(!IsFailed(r),, "Cannot add argument to argument list");
 return list;
CATCH:
 delete list;
 delete arg1;
 return null;
}

ArrayList*
MessageRelay::GetArgumentList(const String &single_parameter)
{
 result r = E_SUCCESS;
 ArrayList *list = null;
 String *arg1 = null;
 list = new Osp::Base::Collection::ArrayList;
 TryCatch(list!=null,, "Cannot instantiate argument list");
 arg1 = new Osp::Base::String(single_parameter);
 TryCatch(arg1!=null,, "Cannot instantiate argument 1");
 r = list->Construct(1);
 TryCatch(!IsFailed(r),, "Cannot construct argument list");
 r = list->Add(*arg1);
 TryCatch(!IsFailed(r),, "Cannot add argument to argument list");
 return list;
CATCH:
 delete list;
 delete arg1;
 return null;
}

ArrayList*
MessageRelay::GetArgumentList(const String &first_parameter, const String &second_parameter)
{
 result r = E_SUCCESS;
 ArrayList *list = null;
 String *arg1 = null;
 String *arg2 = null;
 list = new Osp::Base::Collection::ArrayList;
 TryCatch(list!=null,, "Cannot instantiate argument list");
 arg1 = new Osp::Base::String(first_parameter);
 TryCatch(arg1!=null,, "Cannot instantiate argument 1");
 arg2 = new Osp::Base::String(second_parameter);
 TryCatch(arg1!=null,, "Cannot instantiate argument 2");
 r = list->Construct(2);
 TryCatch(!IsFailed(r),, "Cannot construct argument list");
 r = list->Add(*arg1);
 TryCatch(!IsFailed(r),, "Cannot add argument 1 to argument list");
 r = list->Add(*arg2);
 TryCatch(!IsFailed(r),, "Cannot add argument 2 to argument list");
 return list;
CATCH:
 delete list;
 delete arg1;
 delete arg2;
 return null;
}

ArrayList*
MessageRelay::GetArgumentList(const Object *single_parameter)
{
 result r = E_SUCCESS;
 ArrayList *list = null;
 list = new Osp::Base::Collection::ArrayList;
 TryCatch(list!=null,, "Cannot instantiate argument list");
 r = list->Construct(1);
 TryCatch(!IsFailed(r),, "Cannot construct argument list");
 r = list->Add(*single_parameter);
 TryCatch(!IsFailed(r),, "Cannot add argument to argument list");
 return list;
CATCH:
 delete list;
 return null;
}

Related posts:

  1. Forms Management in Bada (part 3) – Managing Forms
  2. Introduction to Sockets: Simple Low-Level Communication
  3. Tabs Revised: A Better Way To Switch Views
  1. 12 Responses to “Communication improved using C++ templates”

  2. By wit on Jun 17, 2010 | Reply

    great stuff! In fact this open quiet a few possibilities as I see it – I will definitely use templates in my future messaging classes!

    Thank you, Remy!

    :-)

  3. By Remy DAVID on Jun 17, 2010 | Reply

    You are welcome ;)
    Oh and one thing I forgot to mention, always define your templates methods in the header file. It wont work in the .cpp !

  4. By Bryan on Jun 18, 2010 | Reply

    Good tutorial! curious, what did you use to draw the UML diagram?

  5. By Remy DAVID on Jun 18, 2010 | Reply

    Hehe, thanks to wit: yuml.me

  6. By EatenBackToLife on Jun 23, 2010 | Reply

    can’t share your excitement.
    1. dynamic_cast operator is a part of RTTI mechanism which is not supported on Bada
    2. dynamic_cast operator can throw exceptions, which are also not supported

    alas, Bada is still the worst mobile development platform i’ve ever seen..

  7. By Rémy DAVID on Jun 23, 2010 | Reply

    Are you sure it is not supported ? I would assume it does not throw but returns null in case of error.
    At least it is working with the code I mentioned, where static_cast produced a compilation error and C cast produced a runtime error (because of the multiple inheritance).

  8. By EatenBackToLife on Jun 23, 2010 | Reply

    yes, i’m pretty sure that RTTI is not officially supported by Samsung. i’ve seen this in their docs. so if it works now, it doesn’t mean that it will work in the future.
    dynamic_cast operator throws when applied to references (not pointers) – it’s a standard behaviour.
    multiple inheritance has many drawbacks, but i must admit that sometimes it comes very handy. alas, without RTTI support, i’d rather avoid using it..
    my point is (as always): it’s always better to play by rules, no matter how ugly and inconvenient they are.

  9. By wit on Jun 24, 2010 | Reply

    real pirates bend rules :-D !

    dynamic_cast worked for me (for pointers), a while back.
    In general, from the responses on the official forums, if I understand it right, dynamic_cast is supposed to work (at least for pointers)… (?)

  10. By EatenBackToLife on Jun 24, 2010 | Reply

    that’s why pirates usually die young..
    dynamic_cast is evil in most cases anyway, so it’s better not to get used to it. as for exceptions, it’s sometimes easy to forget that dynamic_cast can throw – that’s a trick. again, if there was no multiple inheritance of classes with non-empty implementation, there wouldn’t be such a problem, IIRC.

  11. By codenode on Jun 27, 2010 | Reply

    Let me add a small addition:

    How to get rid of the multiple Inheritance (which is not needed here):

    Assuming that
    Osp::Ui::Controls::Form == Form

    you can easily solve this in that way:
    template
    class MessageRelayT : public Type
    {…};

    class MyForm : public MessageRelayT

    Now we have this hierachy:
    MyForm -> MessageRelayT -> Form

  12. By codenode on Jun 27, 2010 | Reply

    Oh great, it really ate my braces. so, I use [] for now:

    template[class Type]
    class MessageRelayT : public Type
    {…};

    class MyForm : public MessageRelayT[Form]

    Now we have this hierachy:
    MyForm -> MessageRelayT -> Form

  13. By Rémy DAVID on Jun 29, 2010 | Reply

    Once again EatenBackToLife was right, I tested the code under simulator, and it’s working fine.
    But on device the dynamic_cast is not working…
    We have to slightly modify the design and do as codenode said to avoid dynamic_cast.

Post a Comment

Editor's picks

Copyright 2009-2010 BadaDev.com (unless otherwise stated). All rights reserved! Powered by Wordpress!