Thursday, December 4, 2008

Composite Design Pattern

Download the sourcecode from https://github.com/sommukhopadhyay/CompositePattern

Composite design pattern is a structural pattern in which we compose the whole-part relationship in a symmetric hierarchy. The client of the composite treats all the objects in the same fashion.
The whole concept of this design pattern lies in the fact that we can treat a composite object which consists of several other objects the same way as a leaf object. The client never knows that it is working on an object which has many other objects inside it.


Let us try to understand the composite pattern with an example. Here we have defined a class namely Shape, which is acting as the root of all the objects in the example. We have put all the basic functionalities of a graphical object in this class. These functions are Add (for adding a component), Remove (for removing a component), GetChild (for getting a pointer to a child), GetParentOfComponent (which will return the parent of a component) and Draw (to draw a component).

The class diagram of my solution looks like the following:


/*
 * Shape.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef SHAPE_H_
#define SHAPE_H_

#include 
#include "LeafClassTypeException.h"
using namespace std;

class Shape
{
public:

 Shape();
 virtual ~Shape();

 virtual void Add(unsigned int id)
 {
 throw LeafClassTypeException();
 };
 virtual void Remove(unsigned int id){};
 //leaf classes will not override it..however, it will be overridden by the composite class.
 virtual Shape* GetChild(unsigned int id)
 {
 throw LeafClassTypeException();
 };
 //Using this reference the "Chain of Responsibility" can be implemented
 virtual Shape* GetParentOfComponent()
 {
 return ParentOfComponent;
 };
 virtual void SetParentOfComponent(Shape* s)
 {
 ParentOfComponent = s;
 }
 virtual void Display(){};
 virtual Shape* FindItem(unsigned int id); //implementation afterwards


protected:
 Shape* ParentOfComponent;
 unsigned int resource_id;
};

#endif /* SHAPE_H_ */


/*
 * Shape.cpp
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#include "Shape.h"
#include 
#include "global.h"

Shape::Shape() {
 // TODO Auto-generated constructor stub
}

Shape::~Shape() {
 // TODO Auto-generated destructor stub
}

Shape* Shape::FindItem(unsigned int id)
{
 theIterator = Resource_Map.begin();
 while (theIterator != Resource_Map.end())
  {
  theIterator = Resource_Map.find(id);
  Shape* s = (*theIterator).second;
  theIterator++;
  return s;
  }

 return NULL;
}



Now from the Shape class, we have derived other graphic classes, like Point, Line and Rectangle. Among these classes, class Point is working as an helper class to define classes like Line and Rectangle. We have deduced another class called Picture which is composed of these component classes.

/*
 * Point.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef POINT_H_
#define POINT_H_
#include 
#include "Shape.h"
#include "global.h"
using namespace std;

class Point : public Shape
{
public:
 Point():x_Coord(0),y_Coord(0){}
 Point(int x, int y):x_Coord(x), y_Coord(y){}
 Point(const Point& p)
 {
 x_Coord = p.x_Coord;
 y_Coord = p.y_Coord;
 }
 Point& operator = (const Point& p)
 {
 x_Coord = p.x_Coord;
 y_Coord = p.y_Coord;

 return *this;
 }

 virtual void Display()
 {
 cout<<"X Coordinate is:"<<x_Coord<<endl;
 cout<<"Y Coordinate is:"<<y_Coord<<endl;
 }

 int X_COORD()
 {
 return x_Coord;
 }

 int Y_COORD()
 {
 return y_Coord;
 }

 virtual ~Point()
 {
 }

private:

 int x_Coord;
 int y_Coord;
};

#endif /* POINT_H_ */

/*
 * Line.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef LINE_H_
#define LINE_H_

#include 
#include "Shape.h"
#include "global.h"
using namespace std;


//class Line is working as a leaf class.. Lets implement it as a final class
class Line : public Shape
{
 private:
 //private constructor
  Line(unsigned int id):begin(0,0),end(0,0)
  {
  resource_id = id;
  Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
  }
  //private constructor
  Line(unsigned int id, Point a, Point b):begin(a),end(b)
  {
  resource_id = id;
  Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
  }
  //private copy constructor
  Line(const Line& in)
  {

  }



 //private assignment operator
  Line& operator=(const Line& in)
  {
   return *this;
  }

 public:

  virtual void Display()
  {
  cout<<"Begining point is:";
  begin.Display();
  cout<<"End Point is:";
  end.Display();
  }
  static Line* CreateLine(unsigned int id, Point a, Point b)
  {
  return new Line(id,a,b);
  }
private:
 virtual ~Line(){}
 Point begin;
 Point end;
};

#endif /* LINE_H_ */

/*
 * Rectangle.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef RECTANGLE_H_
#define RECTANGLE_H_

#include 
#include "Shape.h"
#include "global.h"
using namespace std;

class Rectangle : public Shape
{
private:
//private constructor
 Rectangle(unsigned int id, Point& p, int width, int height)
 {
 top_left = p;
 top_right = Point(p.X_COORD() + width, p.Y_COORD());
 bottom_left = Point(p.X_COORD() , p.Y_COORD() + height);
 bottom_right = Point(p.X_COORD() + width, p.Y_COORD() + height);
 resource_id = id;
 Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
 }
 //private copy constructor
 Rectangle(const Rectangle& in)
 {

 }
 //private assignment operator
 Rectangle& operator=(const Rectangle& in)
 {
  return *this;
 }
public:
 static Rectangle* CreateRectange(unsigned int id, Point& p, int width, int height)
 {
 return new Rectangle(id, p, width, height);
 }
 virtual ~Rectangle(){}
 virtual void Display()
 {
 cout<<"The four vertices are:"<<endl;
 cout<<"Top Left :" ;
 top_left.Display();
 cout <<"Top Right :";
 top_right.Display();
 cout<<"Bottom Left :";
 bottom_left.Display();
 cout<<"Bottom Right :";
 bottom_right.Display();
 }
private:

 //Attributes
 Point top_left;
 Point top_right;
 Point bottom_left;
 Point bottom_right;
};

#endif /* RECTANGLE_H_ */

The interesting point here is that, we have tried to implement the leaf classes, namely Line and Rectangle as final classes by making their constructors private and providing static member functions to create them.

The Picture class is composed of these leaf objects (Line and Rectangle).

/*
 * Picture.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef PICTURE_H_
#define PICTURE_H_

#include 
#include 

#include "Shape.h"
#include "global.h"
using namespace std;

class Picture : public Shape
{
public:
 Picture(unsigned int id)
 {
  resource_id = id;
  Resource_Map.insert(theMap::value_type(resource_id,(Shape*)this));
 }
 virtual void Display()
 {
  vector<Shape*>::iterator p = Components.begin();
  while (p != Components.end())
  {
  (*p)->Display();
  p++;
  }
 }
//Adds the component with the resource id equal to the passed parameter
 virtual void Add (unsigned int id)
 {
  Shape* s = FindItem(id);
  Components.push_back(s);
  s->SetParentOfComponent(this);
 }

//removes the component from the list with the resource_id equal
//to the parameter passed
 virtual void Remove(unsigned int id)
 {
  Shape* s = FindItem(id);
  vector<Shape*>::iterator p = Components.begin();
  int pos = 0;
  while (p != Components.end())
  {
   if(Components.at(pos) == s)
    break;
   pos++;
   p++;
  }
  Components.erase(p);
  s->SetParentOfComponent(NULL);
 }


 //will return the chile having the id equal to the passed value.
 virtual Shape* GetChild (unsigned int id)
 {
  return FindItem(id);
 }
 virtual ~Picture()
 {
  vector<Shape*>::iterator p = Components.begin();
  int pos = 0;
  while (p != Components.end())
  {
   delete(Components.at(pos));
   p++;
   pos++;

  }//while
  Components.clear();
 }


private:
 vector<Shape*> Components;

};

#endif /* PICTURE_H_ */

The Shape class is called as the Component class, the Line and Rectangle classes are called the Leaf classes and the Picture class is called the Composite class.

Another interesting part of the example is that here every component is identifiable through its resource id. Whenever we create an object (leaf or composite object), it creates a key pair of the id and the pointer to that object and pushes this key into a MAP, from which we can easily search for that component in later times through its resource id.


There are many issues to consider when implementing the composite pattern.

We have defined one function called GetParentOfComponent. This can be useful to traverse the whole hierarchy of parent-child relationship. We have to make sure that any child can have only a composite object as its parent. We have ensured it by defining an Exception class which will be thrown the moment we want to add a component to a leaf object. The exception class can be defined as follows:

/*
 * LeafClassTypeException.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef LEAFCLASSTYPEEXCEPTION_H_
#define LEAFCLASSTYPEEXCEPTION_H_

#include 

using namespace std;

class LeafClassTypeException
{
public:
void printerrormsg()
{
cout<<"This is a leaf class"<<endl;
}
};

#endif /* LEAFCLASSTYPEEXCEPTION_H_ */

The global data has been defined inside global.h & global.cpp files.

/*
 * global.h
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#ifndef GLOBAL_H_
#define GLOBAL_H_

#include 
#include "Shape.h"
using namespace std;

typedef map <unsigned int, Shape*, less<unsigned int> > theMap;

extern theMap Resource_Map;

extern theMap::iterator theIterator;

#endif /* GLOBAL_H_ */

/*
 * global.cpp
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#include "global.h"

theMap Resource_Map;

theMap::iterator theIterator;


The client class looks like the following:

/*
 * main.cpp
 *
 *  Created on: 18-Apr-2015
 *      Author: som
 */

#include 
#include "LeafClassTypeException.h"
#include "Point.h"
#include "Line.h"
#include "Rectangle.h"
#include "Picture.h"

using namespace std;

const int  ID_LINE1 = 1;
const int ID_LINE2 = 2;
const int ID_LINE3 = 3;
const int ID_RECTANGLE1 = 4;
const int ID_PICTURE = 5;

int main()
{
 Point p1(10,20);
 Point p2(30,40);
 Point p3(50,60);
 Point p4(70,80);
 Point p5(100,110);
 Point p6(150,200);
 Line* l1 = Line::CreateLine(ID_LINE1,p1,p2);
 try
 {
 l1->Add(0);
 }
 catch(LeafClassTypeException& e)
 {
 e.printerrormsg();
 }
 Line* l2 = Line::CreateLine(ID_LINE2,p3,p4);
 Line* l3 = Line::CreateLine(ID_LINE3,p5,p6);
 Rectangle* r1 = Rectangle::CreateRectange(ID_RECTANGLE1, p1, 50,25);
 Shape* p = new Picture(ID_PICTURE);
 p->Add(ID_LINE1);
 p->Add(ID_LINE2);
 p->Add(ID_LINE3);
 p->Add(ID_RECTANGLE1);
 (p->GetChild(ID_RECTANGLE1))->Display();
 p->Remove(ID_RECTANGLE1);
 p->Display();
 cout<<p<<endl;
 cout<<l1->GetParentOfComponent()<<endl;

 delete p;

 return 0;
}

It should be noted that the functions like Add and Remove have been defined in the root class. Although for leaf classes, it does not do any meaningful things except throwing an exception, but it gives us transparency, because we can treat all components uniformly.

If we define these functions at the composite class level, then it would give the safety, because any attempt to Add or Remove from the leaf classes would give compile time error, but we would loose the transparency. The composite and the leaf classes will have different interfaces in this case.

The main participants in this design pattern are

Component (Shape) : It basically works as an abstract class which provides a common interface which will be used by the client to treat different classes uniformly. The common functionalities (e.g. Display) have been defined here. Other functionalities like Add, Remove, etc have been put in this class to maximize the role of this interface. The default behavior for Add and Remove has been implemented in such a fashion that for a leaf class, these functions will throw exceptions.
Leaf (Line, Rectangle, etc) : It represents a leaf objects in the composition. Leaf objects cannot have any children.
Composite (Picture) : It stores child components.

Client: It manipulates the objects through the common interface exposed by the Component class.

Friday, November 14, 2008

Test Driven Development

Wednesday, September 10, 2008

Active Objects of Symbian - in the lights of Client-Server Architecture


When I started understanding Active Object framework in Symbian, it was difficult for me to grasp the idea how the front end UI is not frozen, in the event of long running task, even when we don't use multiple threads. But when i started understanding the active object framework in conjunction with the client-server architecture of symbian, I got the idea. I would like to share it with you.

Before we start, i want to throw some lights on the definition of Asynchronous Service Provider and Asynchronous functions in Symbian Active Object and Client-Server architecture. Asynchronous Service Providers are the functions which are fired from a client and returns immediately in that client. However, this function causes another function in the server to run. This server function may be blocking in server side. So we get two sides of a function. We get a non-blocking function in the client-side which initiates another function in the server side, which may be blocking, in the server side. Once the function in the server side finishes, it notifies the client side (which actually initiates the whole chain) about this. These asynchronous functions have TRequestStatus as one of the parameters which is passed as a reference from the client to the server.

These are all theoretical aspects of the Active object and Client-Server framework. Let me give you one practical scenario where this can be used. In this context i would also like to share what actually happens in a normal multi threaded application.

Suppose, we have a communication port which is continuously receiving data from an external source. Suppose we need to develop an application which will read the data and at the same time will render that data in some short of graphical form. So how is it possible?

In symbian environment, we can realize this scenario by employing the Active object framework in conjunction with the client-server architecture. Let me explain it in more details. We may delegate the task of reading the data from the communication port to a server application which will run as a different process than the front end UI application. Of course there are such functionalities already developed in the Symbian and related frameworks. But just for the sake of explanation, we will have to create an asynchronous function in the server which will actually read the data from the communication port. So in the server this function will be blocking. However, we may create an UI application using the active object framework, which will initiate this call to the server and will immediately return in the UI application (non-blocking). The moment, the server finishes reading certain amount of data (say 1024 Kb) and copying it to the UI application's memory area, (remember the UI application and the server are across the process boundary), it will notify the front end UI about this and again start reading the data from the port in the background. On the other hand, the UI application will render the data in the graphical format.

Now let me tell you how this is possible in an Windows application. Once I had developed one such application using the Windows asynchronous I/O pattern and windows event mechanism. There the task of reading of the data  from the communication port was delegated to a background thread. The background thread used to read the data and when it finishes some specific amount it used to fire an event to the front end UI, which then rendered the data in the front end UI.

This is all about theories and scenarios. Now, let me give you a real life symbian code which has got two applications. One is an UI application which has got an engine. This engine is working as an active object for this UI application. Then we have a Symbian Client-Server application. This application has got a client side interface which is a DLL and a Server side implementation which is developed as an EXE. The server has an Asynchronous function which will eventually be called from the UI application.The UI application is linked with the dynamic link library (DLL) of the client-server application.

Let us start from the client-server application. The client has just three exported functions. One is an Asynchronous function and the other if we cancel that function. And the third one is to connect to the server. It looks like the following:


//client.h

class RClient : public RSessionBase
    {
public:
    IMPORT_C TInt Connect();
    IMPORT_C void GetNotifiedWhenEventCompleted(TInt aCount, TDes& aData, TRequestStatus& aStatus);
    IMPORT_C void CancelGetNotifiedWhenEventCompleted();
    };


The implementation of the client looks like the following:


// client.cpp

#include "client.h"
#include "client-server.h"
#include <e32math.h>

// Runs client-side and starts the separate server process
static TInt StartTheServer()
    {
    RProcess server;
    TInt r=server.Create(KServerBinaryName, KNullDesC);
    if (r!=KErrNone)
        return r;
   
    TRequestStatus stat;
    server.Rendezvous(stat);
    if (stat!=KRequestPending)
        server.Kill(0);        // abort startup
    else
        server.Resume();    // logon OK - start the server
   
    User::WaitForRequest(stat);        // wait for start or death
   
    // Check the exit type.
    // We can't use the 'exit reason' because if the server panicked this
    // is set to the panic 'reason' (which may be '0' and cannot thus be distinguished
    // from KErrNone)
    r = server.ExitType();
    if (EExitPanic==r)
        r = KErrGeneral;
    else
        r = stat.Int();
   
    server.Close(); // This is no longer needed
    return r;
    }



EXPORT_C TInt RClient::Connect()
    {
    TInt retry=2;
    for (;;)
        {// Uses system-pool message slots
        TInt r=CreateSession(KServerName,TVersion(1,0,0));
        if ( (KErrNotFound!=r) && (KErrServerTerminated!=r) )
            return (r);
        if (--retry==0)
            return (r);
        r=StartTheServer();
        if ( (KErrNone!=r) && (KErrAlreadyExists!=r) )
            return (r);
        }
    }

EXPORT_C void RClient::GetNotifiedWhenEventCompleted(TInt aCount, TDes& aData, TRequestStatus& aStatus)
    {
    TIpcArgs args(aCount,&aData);
    SendReceive(EGetNotifiedWhenEventCompleted, args, aStatus);
    }
EXPORT_C void RClient::CancelGetNotifiedWhenEventCompleted()
    {
    SendReceive(ECancelGetNotifiedWhenEventCompleted, TIpcArgs());
    }


These are pretty staright forward. I am not going in details about the client server architecture of a symbian application. I am more interested in explaining you about how an asynchrounous function is handled in the client-server and active object framework.

Now let me focus on the server side implementation of this application.

The server header file looks like the following:


// server.h
#ifndef __SERVER_H__
#define __SERVER_H__

#include <e32base.h>
#include "client-server.h"

enum TServerPanic
    {
    EPanicBadDescriptor,
    EPanicNotSupported
    };

void PanicClient(const RMessage2& aMessage,TServerPanic TMyPanic);

const TInt KShutdownDelay=200000; // approx 2 seconds
class CShutdown : public CTimer
    {
public:
    inline CShutdown();
    inline void ConstructL();
    inline void Start();
private:
    void RunL();
    };


inline CShutdown::CShutdown()
    :CTimer(-1)
    {CActiveScheduler::Add(this);}
inline void CShutdown::ConstructL()
    {CTimer::ConstructL();}
inline void CShutdown::Start()
    {After(KShutdownDelay);}


class CMyServer : public CServer2
    {
public:
    static CServer2* NewLC();
    void AddSession();
    void RemoveSession();
private:
    CMyServer();
    void ConstructL();
    // From CServer2
    virtual CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
private:
    TInt iSessionCount;
    CShutdown iShutdown;
    };


inline CMyServer::CMyServer()
    :CServer2(CActive::EPriorityStandard)
    {}


class CAsyncHandler; // Active object class for asynchronous requests

class CMyServerSession : public CSession2
    {
public:
    CMyServerSession();
    void CreateL();
public:
    virtual void ServiceL(const RMessage2& aMessage); // From CSession2
    virtual void ServiceError(const RMessage2& aMessage, TInt aError); // From CSession2
private:
    void GetNotifiedWhenEventCompletedL(const RMessage2& aMessage);
    void CancelGetNotifiedWhenEventCompletedL(const RMessage2& aMessage);
private:
    ~CMyServerSession();
private:
    CAsyncHandler* iAsyncRequestHandler;
    HBufC8* iClientBuf;
    };

inline CMyServerSession::CMyServerSession()
    {}


// Skeleton active object, for asynchronous server requests
// Uses a very basic timer for asynchronicity

class CAsyncHandler : public CActive
    {
public:
    static CAsyncHandler* NewL();
    static CAsyncHandler* NewLC();
    ~CAsyncHandler();
public:
    void ServiceAsyncRequest(const RMessage2& aMessage);
protected:
    CAsyncHandler();
    void ConstructL();
private:
    void DoCancel();
    void RunL();
private:
    RTimer iTimer;
    RMessage2 iMessage;
    };


#endif //__SERVER_H__



And the server implementation file looks like the following:

// server.cpp

#include "server.h"
#include <e32base.h>

_LIT(KDesMsgToServer, "To Server;");
// Called by the CServer framework
void CMyServerSession::CreateL()
    {
    CMyServer* server = static_cast<CMyServer*>(const_cast<CServer2*>(Server()));
    ASSERT(server);
    server->AddSession();
    iAsyncRequestHandler = CAsyncHandler::NewL();
    }

CMyServerSession::~CMyServerSession()
    {
    CMyServer* server = static_cast<CMyServer*>(const_cast<CServer2*>(Server()));
    ASSERT(server);
    server->RemoveSession();
    delete iAsyncRequestHandler;
    delete iClientBuf;
    }

// A bad descriptor error implies a badly programmed client, so panic it
// Report other errors to the client by completing the outstanding request with the error

void CMyServerSession::ServiceError(const RMessage2& aMessage, TInt aError)
    {
    if (KErrBadDescriptor==aError)
        PanicClient(aMessage,EPanicBadDescriptor);
    else
        aMessage.Complete(aError);
    }

// Handle a client request
void CMyServerSession::ServiceL(const RMessage2& aMessage)
    {
    switch (aMessage.Function())
        {
        case EGetNotifiedWhenEventCompleted:
            GetNotifiedWhenEventCompletedL(aMessage);
            break;
           
        case ECancelGetNotifiedWhenEventCompleted:
            CancelGetNotifiedWhenEventCompletedL(aMessage);
            break;
        default:
            PanicClient(aMessage,EPanicNotSupported);
            break;
        }
    }

// Asynchronous method
// message slot 0 contains TInt
// message slot 1 contains TDes8&
void CMyServerSession::GetNotifiedWhenEventCompletedL(const RMessage2& aMessage)
    {
        TInt val0 = aMessage.Int0();
        if (val0!=10)
            aMessage.Complete(KErrGeneral);

        // Determine the length of the client descriptor passed to the server
        TInt clientDesMaxLen = aMessage.GetDesMaxLength(1);
        if (iClientBuf)
        {
            delete iClientBuf;
            iClientBuf = NULL;
        }
  
    //    Make an asynchronous request
    //    for the purpose of example here don't worry about passing the
    //    descriptor retrieved above or modifying it
        iAsyncRequestHandler->ServiceAsyncRequest(aMessage);
    //    iClientBuf is destroyed by later call to this method or destructor
    }

void CMyServerSession::CancelGetNotifiedWhenEventCompletedL(const RMessage2& aMessage)
    {
//    Calls Cancel() on the CAsyncHandler active object
//    which must complete the outstanding async activity and complete
//    the original client-server request
    iAsyncRequestHandler->Cancel();   
    aMessage.Complete(KErrNone);
    }

CServer2* CMyServer::NewLC()
    {
    CMyServer* self=new(ELeave) CMyServer;
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// Starts the server and constructs the shutdown object, starting the timer to ensure that
// the server will exit even if the starting client connection fails
void CMyServer::ConstructL()
    {
    StartL(KServerName);
    iShutdown.ConstructL();
    iShutdown.Start();
    }

// Example doesn't bother checking the version
CSession2* CMyServer::NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const
    {
    return new(ELeave) CMyServerSession();
    }

// Cancel the shutdown timer now, the new session is connected
void CMyServer::AddSession()
    {
    ++iSessionCount;
    iShutdown.Cancel();  // Cancel any outstanding shutdown timer
    }

// Decrement the session counter and start the shutdown timer if the last client has disconnected
void CMyServer::RemoveSession()
    {
    if (--iSessionCount==0)
        iShutdown.Start();
    }


// Initiates server exit when the timer expires
void CShutdown::RunL()
    {
    CActiveScheduler::Stop();
    }

void PanicClient(const RMessage2& aMessage,TServerPanic aPanic)
    {
    _LIT(KPanic,"MyServer");
    aMessage.Panic(KPanic,aPanic);
    }

// Initialize and run the server
static void RunTheServerL()
    {// First create and install the active scheduler
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
    CleanupStack::PushL(scheduler);
    CActiveScheduler::Install(scheduler);

    // create the server
    CMyServer::NewLC();
   
    // Naming the server thread after the server helps to debug panics
    User::LeaveIfError(User::RenameThread(KServerName));
   
    RProcess::Rendezvous(KErrNone);

    // Enter the wait loop
    CActiveScheduler::Start();
   
    // Exited - cleanup the server and scheduler
    CleanupStack::PopAndDestroy(2, scheduler);
    }

// Server process entry-point
TInt E32Main()
    {
    __UHEAP_MARK; // Heap checking
   
    CTrapCleanup* cleanup=CTrapCleanup::New();
    TInt r=KErrNoMemory;
    if (cleanup)
        {
        TRAP(r,RunTheServerL());
        delete cleanup;
        }
    __UHEAP_MARKEND;
    return r;
    }


The class CAsyncHandler has been implemented as the following:


// asynchandler.cpp

// Skeleton active object, for asynchronous server requests

#include <e32base.h>
#include "server.h"

CAsyncHandler* CAsyncHandler::NewL()
    {
    CAsyncHandler* me = CAsyncHandler::NewLC();
    CleanupStack::Pop(me);
    return (me);
    }

CAsyncHandler* CAsyncHandler::NewLC()
    {
    CAsyncHandler* me = new (ELeave) CAsyncHandler();
    CleanupStack::PushL(me);
    me->ConstructL();
    return (me);
    }

CAsyncHandler::~CAsyncHandler()
    {
    Cancel();
    iTimer.Close();   
    }

CAsyncHandler::CAsyncHandler()
: CActive(EPriorityStandard)
    {
    CActiveScheduler::Add(this);
    }

void CAsyncHandler::ConstructL()
    {
    User::LeaveIfError(iTimer.CreateLocal());
    }

void CAsyncHandler::ServiceAsyncRequest(const RMessage2& aMessage)
    {// Only allow one request to be submitted at a time
    _LIT(KOutstandingRequestPanic, "InUse");
    __ASSERT_ALWAYS(!IsActive(), User::Panic(KOutstandingRequestPanic, KErrInUse));
    iMessage = aMessage;
    iTimer.After(iStatus, 2000000); // Set the RTimer to expire in 2 seconds
    SetActive(); // Mark this object active   
    }

void CAsyncHandler::DoCancel()
    {
    iTimer.Cancel();
    iMessage.Complete(KErrCancel);
    }

void CAsyncHandler::RunL()
    {
    iMessage.Complete(iStatus.Int());
    }



The client-server.h file looks like the following:

// client-server.h
#ifndef CLIENTSERVER_H__
#define CLIENTSERVER_H__

#include <e32std.h>
#include <s32std.h>

_LIT(KServerName,"TestServer");// The server's identity within the client-server framework
_LIT(KServerBinaryName,"server"); // The name of the server binary (dll or exe)

#ifdef __WINS__
const TInt KMinServerHeapSize=0x1000;
const TInt KMaxServerHeapSize=0x1000000;
#endif

enum TClientServerCommands
    {
    EGetNotifiedWhenEventCompleted,
    ECancelGetNotifiedWhenEventCompleted
    };

#endif // CLIENTSERVER_H__


So this is all about the client-server application of the example. This client-server application will provide the basis of the Asynchronous signal handling in the Active Object framework.

Please see the function void CMyServerSession::GetNotifiedWhenEventCompletedL(const RMessage2& aMessage).

Towards the end of this function we are calling iAsyncRequestHandler->ServiceAsyncRequest(aMessage). Please remember I am not interested what the server is doing with the data that the client passes to it. I am more interested in explaining to you how the Asynchronous function is being handled by the server and in turn how it signals the Front-end UI.

If we delve into the function


void CAsyncHandler::ServiceAsyncRequest(const RMessage2& aMessage)
    {// Only allow one request to be submitted at a time
    _LIT(KOutstandingRequestPanic, "InUse");
    __ASSERT_ALWAYS(!IsActive(), User::Panic(KOutstandingRequestPanic, KErrInUse));
    iMessage = aMessage;
    iTimer.After(iStatus, 2000000); // Set the RTimer to expire in 2 seconds
    SetActive(); // Mark this object active   
    }


we will find that it initiates a delay (iTimer.After (iStatus, 2000000) and at the end it calls SetActive which initiates the Active Scheduler of the server to call the RunL().

This RunL() function is implemented as the following:
<code>
void CAsyncHandler::RunL()
    {
    iMessage.Complete(iStatus.Int());
    }


We find that it calls Complete on the iMessage. This function Complete actually initiates an inter process communication and signals the front end UI application about the completion of the server-side task.

Now let us concentrate on the front end UI application. This is a simple UI helloworld application created through the carbide c++ wizard. This application has got an engine which looks like the following:

//engine.h

#ifndef __ENGINE_h__
#define __ENGINE_h__

#include <e32base.h>

#include "../../clientserver/inc/client.h"

//forward declaration
class CActiveObjectTestAppView;


class MObserver
    {
public:
    virtual void CallbackFunction_BeginProcessing() = 0;
   
    virtual void CallbackFunction_EndProcessing() = 0;
    };


class CEngine : public CActive
    {
public:
    ~CEngine();
   
    static CEngine* NewL(MObserver& aObserver);
   
private:
    //construction
    CEngine(MObserver& aObserver);
    void ConstructL();
 
public:
   
    //from CActive
    virtual void RunL();
    virtual void DoCancel();
   
    //new function.. Asynchronous service provider
    void MakeAsyncCall(TRequestStatus& aStatus);
   
private:
    //not owned
    MObserver& iObserver;
    RClient session;
    };

#endif



As you can see, this is working as an active object for the Front end UI. There is another M class called MObserver which provides the necessary call back functionalities for this UI application. This MObserver class will be realized by the CActiveObjectTestAppUi class of the application.

The engine class implementation will look like the following:

//engine.cpp

//#include <e32base.h>

#include "engine.h"
#include "ActiveObjectTestAppView.h"
//#include "client.h"

_LIT(KDesMsgToServer, "To Server;");

CEngine::CEngine(MObserver& aObserver):CActive(CActive::EPriorityStandard),iObserver(aObserver)
    {
    }

CEngine::~CEngine()
    {
    Cancel();
    }

void CEngine::ConstructL()
    {
    CActiveScheduler::Add(this);
    TInt ret = session.Connect();
    User::LeaveIfError(ret);
    }

CEngine* CEngine::NewL(MObserver& aObserver)
    {
    CEngine* self = new(ELeave) CEngine(aObserver);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

void CEngine::MakeAsyncCall(TRequestStatus& aStatus)
    {
    TBuf<20> myBuf(KDesMsgToServer);
    session.GetNotifiedWhenEventCompleted(10, myBuf, aStatus);
    iObserver.CallbackFunction_BeginProcessing();
    SetActive();
    }

void CEngine::RunL()
    {
    iObserver.CallbackFunction_EndProcessing();
    }

void CEngine::DoCancel()
    {
    Cancel();
    }


As this is clear the task of the engine is to establish a connection with the client-server application and issue an asynchronous call through its MakeAsyncCall(TRequestStatus& aStatus) function.

Now if you look into the MakeAsyncCall function, we will find that after issuing the exported function GetNotifiedWhenEventCompleted of the client interface of the client-server application, it is calling the Observer's CallbackFunction_BeginProcessing(). This function actually makes the UI look responding with some message. In the example application I have rendered the text in the view as "Beginning...".

So, now the processing in the server of the client-server application has started. As in the server side CAsyncHandler::ServiceAsyncRequest function it creates some delay and then signals active scheduler of the fron end UI application. This active scheduler will then call the RunL function. Here this RunL() function simply refreshes the screenwith the message "End...".

Hence you will find two messages in the UI application - "Beginning..." and after some delay "End...". Thus the UI looks responding when thw server does some background task.The application will look like the following:







Let me show you how the AppUi class has been created in the application. It looks like the following:


/*
 ============================================================================
 Name        : ActiveObjectTestAppUi.h
 Author      : som
 Copyright   : Your copyright notice
 Description : Declares UI class for application.
 ============================================================================
 */

#ifndef __ACTIVEOBJECTTESTAPPUI_h__
#define __ACTIVEOBJECTTESTAPPUI_h__

// INCLUDES
#include <aknappui.h>
#include "engine.h"

// FORWARD DECLARATIONS
class CActiveObjectTestAppView;
class CEngine;
// CLASS DECLARATION
/**
 * CActiveObjectTestAppUi application UI class.
 * Interacts with the user through the UI and request message processing
 * from the handler class
 */
class CActiveObjectTestAppUi : public CAknAppUi, public MObserver
    {
public:
    // Constructors and destructor

    /**
     * ConstructL.
     * 2nd phase constructor.
     */
    void ConstructL();

    /**
     * CActiveObjectTestAppUi.
     * C++ default constructor. This needs to be public due to
     * the way the framework constructs the AppUi
     */
    CActiveObjectTestAppUi();

    /**
     * ~CActiveObjectTestAppUi.
     * Virtual Destructor.
     */
    virtual ~CActiveObjectTestAppUi();

private:
    // Functions from base classes

    /**
     * From CEikAppUi, HandleCommandL.
     * Takes care of command handling.
     * @param aCommand Command to be handled.
     */
    void HandleCommandL(TInt aCommand);

    /**
     *  HandleStatusPaneSizeChange.
     *  Called by the framework when the application status pane
     *  size is changed.
     */
    void HandleStatusPaneSizeChange();

    /**
     *  From CCoeAppUi, HelpContextL.
     *  Provides help context for the application.
     *  size is changed.
     */
    CArrayFix<TCoeHelpContext>* HelpContextL() const;
   
    CEngine* GetEnginePtr();
   
    //from MObserver
    void CallbackFunction_BeginProcessing();
   
    void CallbackFunction_EndProcessing();
       

private:
    // Data

    /**
     * The application view
     * Owned by CActiveObjectTestAppUi
     */
    CActiveObjectTestAppView* iAppView;
   
    //The engine is owned by CActiveObjectTestAppUi
    CEngine* iEngine;

    };

#endif // __ACTIVEOBJECTTESTAPPUI_h__
// End of File



And the implementation looks like the following:

/*
 ============================================================================
 Name        : ActiveObjectTestAppUi.cpp
 Author      : som
 Copyright   : Your copyright notice
 Description : CActiveObjectTestAppUi implementation
 ============================================================================
 */

// INCLUDE FILES
#include <avkon.hrh>
#include <aknmessagequerydialog.h>
#include <aknnotewrappers.h>
#include <stringloader.h>
#include <f32file.h>
#include <s32file.h>
#include <hlplch.h>

#include <ActiveObjectTest_0xEB0B3448.rsg>

//#include "ActiveObjectTest_0xEB0B3448.hlp.hrh"
#include "ActiveObjectTest.hrh"
#include "ActiveObjectTest.pan"
#include "ActiveObjectTestApplication.h"
#include "ActiveObjectTestAppUi.h"
#include "ActiveObjectTestAppView.h"
//#include "engine.h"
_LIT(KFileName, "C:\private\EB0B3448\ActiveObjectTest.txt");
_LIT(KText, "Active Object Test");
_LIT(KBeginningProcessingText, "Beginning...");
_LIT(KEndProcessingText, "End...");
// ============================ MEMBER FUNCTIONS ===============================


// -----------------------------------------------------------------------------
// CActiveObjectTestAppUi::ConstructL()
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CActiveObjectTestAppUi::ConstructL()
    {
    // Initialise app UI with standard value.
    BaseConstructL(CAknAppUi::EAknEnableSkin);

    // Create view object
    iAppView = CActiveObjectTestAppView::NewL(ClientRect() );

    // Create a file to write the text to
    TInt err = CCoeEnv::Static()->FsSession().MkDirAll(KFileName);
    if ( (KErrNone != err) && (KErrAlreadyExists != err))
        {
        return;
        }

    RFile file;
    err = file.Replace(CCoeEnv::Static()->FsSession(), KFileName, EFileWrite);
    CleanupClosePushL(file);
    if (KErrNone != err)
        {
        CleanupStack::PopAndDestroy(1); // file
        return;
        }

    RFileWriteStream outputFileStream(file);
    CleanupClosePushL(outputFileStream);
    outputFileStream << KText;

    CleanupStack::PopAndDestroy(2); // outputFileStream, file
   
    //instantiation of the engine
    iEngine = CEngine::NewL(*this);

    }
// -----------------------------------------------------------------------------
// CActiveObjectTestAppUi::CActiveObjectTestAppUi()
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CActiveObjectTestAppUi::CActiveObjectTestAppUi()
    {
    // No implementation required
    }

// -----------------------------------------------------------------------------
// CActiveObjectTestAppUi::~CActiveObjectTestAppUi()
// Destructor.
// -----------------------------------------------------------------------------
//
CActiveObjectTestAppUi::~CActiveObjectTestAppUi()
    {
    if (iAppView)
        {
        delete iAppView;
        iAppView = NULL;
        }
    }

// -----------------------------------------------------------------------------
// CActiveObjectTestAppUi::HandleCommandL()
// Takes care of command handling.
// -----------------------------------------------------------------------------
//
void CActiveObjectTestAppUi::HandleCommandL(TInt aCommand)
    {
    switch (aCommand)
        {
        case EEikCmdExit:
        case EAknSoftkeyExit:
            Exit();
            break;

        case ECommand1:
            {
            //Here we are calling the Asynchronous function
            iEngine->MakeAsyncCall(GetEnginePtr()->iStatus);
            }
            break;

        //The rest of the function has not been touched. its the default created by the wizard
        case ECommand2:
            {
           
            RFile rFile;

            //Open file where the stream text is
            User::LeaveIfError(rFile.Open(CCoeEnv::Static()->FsSession(), KFileName, EFileStreamText));//EFileShareReadersOnly));// EFileStreamText));
            CleanupClosePushL(rFile);

            // copy stream from file to RFileStream object
            RFileReadStream inputFileStream(rFile);
            CleanupClosePushL(inputFileStream);

            // HBufC descriptor is created from the RFileStream object.
            HBufC* fileData = HBufC::NewLC(inputFileStream, 32);

            CAknInformationNote* informationNote;

            informationNote = new ( ELeave ) CAknInformationNote;
            // Show the information Note
            informationNote->ExecuteLD( *fileData);

            // Pop loaded resources from the cleanup stack
            CleanupStack::PopAndDestroy(3); // filedata, inputFileStream, rFile
            }
            break;
        case EHelp:
            {
           
            CArrayFix<TCoeHelpContext>* buf = CCoeAppUi::AppHelpContextL();
            HlpLauncher::LaunchHelpApplicationL(iEikonEnv->WsSession(), buf);
            }
            /*
            TRequestStatus status;
            iAppView->iEngine->MakeAsyncCall(status);
            */
            break;
        case EAbout:
            {
           
            CAknMessageQueryDialog* dlg = new (ELeave)CAknMessageQueryDialog();
            dlg->PrepareLC(R_ABOUT_QUERY_DIALOG);
            HBufC* title = iEikonEnv->AllocReadResourceLC(R_ABOUT_DIALOG_TITLE);
            dlg->QueryHeading()->SetTextL(*title);
            CleanupStack::PopAndDestroy(); //title
            HBufC* msg = iEikonEnv->AllocReadResourceLC(R_ABOUT_DIALOG_TEXT);
            dlg->SetMessageTextL(*msg);
            CleanupStack::PopAndDestroy(); //msg
            dlg->RunLD();
            }
            /*
            TRequestStatus status;
            iAppView->iEngine->MakeAsyncCall(status);
            break;
            */
            break;
        default:
            Panic(EActiveObjectTestUi);
            break;
        }
    }
// -----------------------------------------------------------------------------
//  Called by the framework when the application status pane
//  size is changed.  Passes the new client rectangle to the
//  AppView
// -----------------------------------------------------------------------------
//
void CActiveObjectTestAppUi::HandleStatusPaneSizeChange()
    {
    iAppView->SetRect(ClientRect() );
    }

CArrayFix<TCoeHelpContext>* CActiveObjectTestAppUi::HelpContextL() const
    {
#warning "Please see comment about help and UID3..."
    // Note: Help will not work if the application uid3 is not in the
    // protected range.  The default uid3 range for projects created
    // from this template (0xE0000000 - 0xEFFFFFFF) are not in the protected range so that they
    // can be self signed and installed on the device during testing.
    // Once you get your official uid3 from Symbian Ltd. and find/replace
    // all occurrences of uid3 in your project, the context help will
    // work.
    CArrayFixFlat<TCoeHelpContext>* array = new(ELeave)CArrayFixFlat<TCoeHelpContext>(1);
    CleanupStack::PushL(array);
    //array->AppendL(TCoeHelpContext(KUidActiveObjectTestApp,
            //KGeneral_Information));
    CleanupStack::Pop(array);
    return array;
    }

//Gets a pointer to the engine object
CEngine* CActiveObjectTestAppUi::GetEnginePtr()
    {
    return iEngine;
    }
void CActiveObjectTestAppUi::CallbackFunction_BeginProcessing()
    {
    iAppView->UpdateScreenText(KBeginningProcessingText);
    }

void CActiveObjectTestAppUi::CallbackFunction_EndProcessing()
    {
    iAppView->UpdateScreenText(KEndProcessingText);
    }

// End of File



Please look at the void CActiveObjectTestAppUi::HandleCommandL(TInt aCommand) funnction.

Go to case ECommand1:

Here it becomes clear how we call the Asynchronous function through the menu commands.

I have changed the Draw function of the View class as following:


void CActiveObjectTestAppView::Draw(const TRect& /*aRect*/) const
    {
    // Get the standard graphics context
    CWindowGc& gc = SystemGc();

    // Gets the control's extent
    TRect drawRect(Rect());

    // Clears the screen
    gc.Clear(drawRect);
   
    const CFont* font;
    font = iEikonEnv->TitleFont();
   
    gc.UseFont(font);
   
    TInt baseLineOffset = drawRect.Height()/2;
   
    gc.DrawText(iScreenText,drawRect, baseLineOffset, CGraphicsContext::ECenter,0);
   
    }



There is another function added in the view class which is as follows:

void CActiveObjectTestAppView::UpdateScreenText(const TDesC16& msg)
    {
    iScreenText.Copy(msg);
    DrawNow();
    }


So let me recapitulate the basic functionalities of the Active object, Asynchronous function and Client-Server framework.
The steps are as follows;

  1. The front end UI calls some asynchronous function of the engine through its menu command
  2. The Observer's callback function is called to notify the UI about this state
  3. The engine delegates the task to a background server application
  4. The server finishes this task asynchronously and signals the Active Scheduler of the UI application through inter process communication
  5. The Active Scheduler of the UI application calls the RunL() function
  6. Inside this RunL() function we update the Screen again stating the status of the task

Actually we implement this RunL() function of the UI to implement a state pattern wherein we call different Asynchronous functions of the server in each state and update the UI accordingly.

There is another point that I want to touch about. See how the cyclic reference between two concrete classes of the front end UI (CEngine and the CActiveObjectTestAppUi) has been implemented through an M class (MObserver).

I hope I am able to throw some lights on the haziness of Active Object and Client-Server Architecture. If this helps people, specifically the newbies of Symbian, I will feel good.

The screen capture of the application will look like the following:

video



Reference: The book for Accredited Symbian Developer exam and the associated code


Note: Here goes the source code of the full application...

Share