active object of symbian in the lights of client server architecture

22
Active Objects of Symbian in the lights of Client-Server architecture by Somenath Mukhopadhyay [email protected] 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

Upload: somenath-mukhopadhyay

Post on 18-Dec-2014

618 views

Category:

Technology


0 download

DESCRIPTION

A discussion on Symbian Active Object framework

TRANSCRIPT

Page 1: Active object of Symbian in the lights of client server architecture

Active Objects ofSymbian in the lights

of Client-Serverarchitecture

by

Somenath [email protected]

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

Before we start, i want to throw some lights on the definition of Asynchronous ServiceProvider and Asynchronous functions in Symbian Active Object and Client-Serverarchitecture. Asynchronous Service Providers are the functions which are fired from a clientand returns immediately in that client. However, this function causes another function in theserver to run. This server function may be blocking in server side. So we get two sides of afunction. We get a non-blocking function in the client-side which initiates another function inthe server side, which may be blocking, in the server side. Once the function in the serverside 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 ispassed as a reference from the client to the server.

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

Suppose, we have a communication port which is continuously receiving data from anexternal source. Suppose we need to develop an application which will read the data and atthe 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 objectframework in conjunction with the client-server architecture. Let me explain it in more

Page 2: Active object of Symbian in the lights of client server architecture

details. We may delegate the task of reading the data from the communication port to aserver application which will run as a different process than the front end UI application. Ofcourse there are such functionalities already developed in the Symbian and relatedframeworks. But just for the sake of explanation, we will have to create an asynchronousfunction in the server which will actually read the data from the communication port. So inthe server this function will be blocking. However, we may create an UI application using theactive object framework, which will initiate this call to the server and will immediately returnin the UI application (non-blocking). The moment, the server finishes reading certain amountof data (say 1024 Kb) and copying it to the UI application's memory area, (remember the UIapplication and the server are across the process boundary), it will notify the front end UIabout this and again start reading the data from the port in the background. On the otherhand, 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 onesuch application using the Windows asynchronous I/O pattern and windows eventmechanism. There the task of reading of the data from the communication port wasdelegated to a background thread. The background thread used to read the data and when itfinishes some specific amount it used to fire an event to the front end UI, which thenrendered the data in the front end UI.

This is all about theories and scenarios. Now, let me give you a real life symbian code whichhas got two applications. One is an UI application which has got an engine. This engine isworking as an active object for this UI application. Then we have a Symbian Client-Serverapplication. This application has got a client side interface which is a DLL and a Server sideimplementation which is developed as an EXE. The server has an Asynchronous functionwhich will eventually be called from the UI application.The UI application is linked with thedynamic 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 oneis 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>

Page 3: Active object of Symbian in the lights of client server architecture

// Runs client-side and starts the separate server processstatic 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);

Page 4: Active object of Symbian in the lights of client server architecture

}EXPORT_C void RClient::CancelGetNotifiedWhenEventCompleted() { SendReceive(ECancelGetNotifiedWhenEventCompleted, TIpcArgs()); }

These are pretty staright forward. I am not going in details about the client serverarchitecture of a symbian application. I am more interested in explaining you about how anasynchrounous 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 secondsclass 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 {

Page 5: Active object of Symbian in the lights of client server architecture

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 CSession2private: 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();

Page 6: Active object of Symbian in the lights of client server architecture

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 frameworkvoid 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); }

Page 7: Active object of Symbian in the lights of client server architecture

// Handle a client requestvoid 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()

Page 8: Active object of Symbian in the lights of client server architecture

{ 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 failsvoid CMyServer::ConstructL() { StartL(KServerName); iShutdown.ConstructL(); iShutdown.Start(); }

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

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

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

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

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

// Initialize and run the serverstatic void RunTheServerL() {// First create and install the active scheduler

Page 9: Active object of Symbian in the lights of client server architecture

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-pointTInt 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()

Page 10: Active object of Symbian in the lights of client server architecture

{ 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>

Page 11: Active object of Symbian in the lights of client server architecture

_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 applicationwill provide the basis of the Asynchronous signal handling in the Active Object framework.

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

Towards the end of this function we are callingiAsyncRequestHandler->ServiceAsyncRequest(aMessage). Please remember I am notinterested what the server is doing with the data that the client passes to it. I am moreinterested in explaining to you how the Asynchronous function is being handled by the serverand 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 callsSetActive 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

Page 12: Active object of Symbian in the lights of client server architecture

inter process communication and signals the front end UI application about the completion ofthe server-side task.

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

//engine.h

#ifndef __ENGINE_h__#define __ENGINE_h__

#include <e32base.h>

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

//forward declarationclass 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;

Page 13: Active object of Symbian in the lights of client server architecture

};

#endif

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

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();

Page 14: Active object of Symbian in the lights of client server architecture

}

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-serverapplication 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 exportedfunction GetNotifiedWhenEventCompleted of the client interface of the client-serverapplication, it is calling the Observer's CallbackFunction_BeginProcessing(). This functionactually makes the UI look responding with some message. In the example application I haverendered the text in the view as "Beginning...".

So, now the processing in the server of the client-server application has started. As in theserver side CAsyncHandler::ServiceAsyncRequest function it creates some delay and thensignals active scheduler of the fron end UI application. This active scheduler will then call theRunL 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.

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

/* ============================================================================ 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"

Page 15: Active object of Symbian in the lights of client server architecture

// FORWARD DECLARATIONSclass 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.

Page 16: Active object of Symbian in the lights of client server architecture

*/ 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>

Page 17: Active object of Symbian in the lights of client server architecture

//#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);

}

Page 18: Active object of Symbian in the lights of client server architecture

// -----------------------------------------------------------------------------// 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));

Page 19: Active object of Symbian in the lights of client server architecture

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; } }

Page 20: Active object of Symbian in the lights of client server architecture

// -----------------------------------------------------------------------------// 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 thatthey // 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 objectCEngine* 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:

Page 21: Active object of Symbian in the lights of client server architecture

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 functionand Client-Server framework.The steps are as follows;

1. The front end UI calls some asynchronous function of the engine through its menucommand

2. The Observer's callback function is called to notify the UI about this state3. The engine delegates the task to a background server application4. The server finishes this task asynchronously and signals the Active Scheduler of the UI

application through inter process communication5. The Active Scheduler of the UI application calls the RunL() function6. 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 whereinwe call different Asynchronous functions of the server in each state and update the UIaccordingly.

Page 22: Active object of Symbian in the lights of client server architecture

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

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

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