SlideShare une entreprise Scribd logo
1  sur  22
Télécharger pour lire hors ligne
Active Objects of
Symbian in the lights
of Client-Server
architecture
by
Somenath Mukhopadhyay
som.mukhopadhyay@gmail.com
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.
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:privateEB0B3448ActiveObjectTest.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
2.
3.
4.
5.
6.

command
The Observer's callback function is called to notify the UI about this state
The engine delegates the task to a background server application
The server finishes this task asynchronously and signals the Active Scheduler of the UI
application through inter process communication
The Active Scheduler of the UI application calls the RunL() function
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.
Reference: The book for Accredited Symbian Developer exam and the associated code

Contenu connexe

Tendances

Spring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topicsSpring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topicsGuy Nir
 
Medium TechTalk — iOS
Medium TechTalk — iOSMedium TechTalk — iOS
Medium TechTalk — iOSjimmyatmedium
 
Spring 3.x - Spring MVC
Spring 3.x - Spring MVCSpring 3.x - Spring MVC
Spring 3.x - Spring MVCGuy Nir
 
Introduction to Spring MVC
Introduction to Spring MVCIntroduction to Spring MVC
Introduction to Spring MVCRichard Paul
 
Ninad cucumber rails
Ninad cucumber railsNinad cucumber rails
Ninad cucumber railsninad23p
 
Spring MVC Architecture Tutorial
Spring MVC Architecture TutorialSpring MVC Architecture Tutorial
Spring MVC Architecture TutorialJava Success Point
 
Java Server Faces (JSF) - advanced
Java Server Faces (JSF) - advancedJava Server Faces (JSF) - advanced
Java Server Faces (JSF) - advancedBG Java EE Course
 
Ember Reusable Components and Widgets
Ember Reusable Components and WidgetsEmber Reusable Components and Widgets
Ember Reusable Components and WidgetsSergey Bolshchikov
 
Brief Introduction to Ember
Brief Introduction to EmberBrief Introduction to Ember
Brief Introduction to EmberVinay B
 
Integrating Servlets and JSP (The MVC Architecture)
Integrating Servlets and JSP  (The MVC Architecture)Integrating Servlets and JSP  (The MVC Architecture)
Integrating Servlets and JSP (The MVC Architecture)Amit Ranjan
 
Scaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby undergroundScaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby undergroundOmer Gazit
 
OpenWebBeans/Web Beans
OpenWebBeans/Web BeansOpenWebBeans/Web Beans
OpenWebBeans/Web BeansGurkan Erdogdu
 

Tendances (17)

SpringMVC
SpringMVCSpringMVC
SpringMVC
 
Spring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topicsSpring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topics
 
Medium TechTalk — iOS
Medium TechTalk — iOSMedium TechTalk — iOS
Medium TechTalk — iOS
 
Spring 3.x - Spring MVC
Spring 3.x - Spring MVCSpring 3.x - Spring MVC
Spring 3.x - Spring MVC
 
Spring MVC Basics
Spring MVC BasicsSpring MVC Basics
Spring MVC Basics
 
Introduction to Spring MVC
Introduction to Spring MVCIntroduction to Spring MVC
Introduction to Spring MVC
 
Ninad cucumber rails
Ninad cucumber railsNinad cucumber rails
Ninad cucumber rails
 
Spring MVC Architecture Tutorial
Spring MVC Architecture TutorialSpring MVC Architecture Tutorial
Spring MVC Architecture Tutorial
 
Java Server Faces (JSF) - advanced
Java Server Faces (JSF) - advancedJava Server Faces (JSF) - advanced
Java Server Faces (JSF) - advanced
 
Ember Reusable Components and Widgets
Ember Reusable Components and WidgetsEmber Reusable Components and Widgets
Ember Reusable Components and Widgets
 
Brief Introduction to Ember
Brief Introduction to EmberBrief Introduction to Ember
Brief Introduction to Ember
 
Implicit object.pptx
Implicit object.pptxImplicit object.pptx
Implicit object.pptx
 
Integrating Servlets and JSP (The MVC Architecture)
Integrating Servlets and JSP  (The MVC Architecture)Integrating Servlets and JSP  (The MVC Architecture)
Integrating Servlets and JSP (The MVC Architecture)
 
Scaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby undergroundScaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby underground
 
Spring Web MVC
Spring Web MVCSpring Web MVC
Spring Web MVC
 
OpenWebBeans/Web Beans
OpenWebBeans/Web BeansOpenWebBeans/Web Beans
OpenWebBeans/Web Beans
 
2 Asp Dot Net Ajax Extensions
2 Asp Dot Net Ajax Extensions2 Asp Dot Net Ajax Extensions
2 Asp Dot Net Ajax Extensions
 

Similaire à Active object of Symbian in the lights of client server architecture

Android service, aidl - day 1
Android service, aidl - day 1Android service, aidl - day 1
Android service, aidl - day 1Utkarsh Mankad
 
Rits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce LightningRits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce LightningRight IT Services
 
Composable and streamable Play apps
Composable and streamable Play appsComposable and streamable Play apps
Composable and streamable Play appsYevgeniy Brikman
 
Tips and Tricks for new async web client capabilities on model driven apps
Tips and Tricks for new async web client capabilities on model driven appsTips and Tricks for new async web client capabilities on model driven apps
Tips and Tricks for new async web client capabilities on model driven appsMehdi El Amri
 
Angular resolver tutorial
Angular resolver tutorialAngular resolver tutorial
Angular resolver tutorialKaty Slemon
 
Angular 16 – the rise of Signals
Angular 16 – the rise of SignalsAngular 16 – the rise of Signals
Angular 16 – the rise of SignalsCoding Academy
 
Reactive Application Using METEOR
Reactive Application Using METEORReactive Application Using METEOR
Reactive Application Using METEORNodeXperts
 
Understanding router state in angular 7 passing data through angular router s...
Understanding router state in angular 7 passing data through angular router s...Understanding router state in angular 7 passing data through angular router s...
Understanding router state in angular 7 passing data through angular router s...Katy Slemon
 
Server side programming
Server side programming Server side programming
Server side programming javed ahmed
 
Reactotron - A Debugging Agent
Reactotron -  A Debugging AgentReactotron -  A Debugging Agent
Reactotron - A Debugging AgentMatthieu Vachon
 
Architecting single-page front-end apps
Architecting single-page front-end appsArchitecting single-page front-end apps
Architecting single-page front-end appsZohar Arad
 
Part 2 generating a client_from_wsdl
Part 2 generating a client_from_wsdlPart 2 generating a client_from_wsdl
Part 2 generating a client_from_wsdlkrishmdkk
 
Reactive application using meteor
Reactive application using meteorReactive application using meteor
Reactive application using meteorSapna Upreti
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "FDConf
 
Javascript internals
Javascript internalsJavascript internals
Javascript internalsAyush Sharma
 

Similaire à Active object of Symbian in the lights of client server architecture (20)

Android service, aidl - day 1
Android service, aidl - day 1Android service, aidl - day 1
Android service, aidl - day 1
 
Rits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce LightningRits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce Lightning
 
React loadable
React loadableReact loadable
React loadable
 
Asynchronyin net
Asynchronyin netAsynchronyin net
Asynchronyin net
 
OneTeam Media Server
OneTeam Media ServerOneTeam Media Server
OneTeam Media Server
 
Composable and streamable Play apps
Composable and streamable Play appsComposable and streamable Play apps
Composable and streamable Play apps
 
Tips and Tricks for new async web client capabilities on model driven apps
Tips and Tricks for new async web client capabilities on model driven appsTips and Tricks for new async web client capabilities on model driven apps
Tips and Tricks for new async web client capabilities on model driven apps
 
Angular resolver tutorial
Angular resolver tutorialAngular resolver tutorial
Angular resolver tutorial
 
Angular 16 – the rise of Signals
Angular 16 – the rise of SignalsAngular 16 – the rise of Signals
Angular 16 – the rise of Signals
 
Reactive Application Using METEOR
Reactive Application Using METEORReactive Application Using METEOR
Reactive Application Using METEOR
 
Understanding router state in angular 7 passing data through angular router s...
Understanding router state in angular 7 passing data through angular router s...Understanding router state in angular 7 passing data through angular router s...
Understanding router state in angular 7 passing data through angular router s...
 
Server side programming
Server side programming Server side programming
Server side programming
 
Reactotron - A Debugging Agent
Reactotron -  A Debugging AgentReactotron -  A Debugging Agent
Reactotron - A Debugging Agent
 
Architecting single-page front-end apps
Architecting single-page front-end appsArchitecting single-page front-end apps
Architecting single-page front-end apps
 
Part 2 generating a client_from_wsdl
Part 2 generating a client_from_wsdlPart 2 generating a client_from_wsdl
Part 2 generating a client_from_wsdl
 
Mobile Application Development class 008
Mobile Application Development class 008Mobile Application Development class 008
Mobile Application Development class 008
 
NodeJS @ ACS
NodeJS @ ACSNodeJS @ ACS
NodeJS @ ACS
 
Reactive application using meteor
Reactive application using meteorReactive application using meteor
Reactive application using meteor
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
Javascript internals
Javascript internalsJavascript internals
Javascript internals
 

Plus de Somenath Mukhopadhyay

Significance of private inheritance in C++...
Significance of private inheritance in C++...Significance of private inheritance in C++...
Significance of private inheritance in C++...Somenath Mukhopadhyay
 
Arranging the words of a text lexicographically trie
Arranging the words of a text lexicographically   trieArranging the words of a text lexicographically   trie
Arranging the words of a text lexicographically trieSomenath Mukhopadhyay
 
Generic asynchronous HTTP utility for android
Generic asynchronous HTTP utility for androidGeneric asynchronous HTTP utility for android
Generic asynchronous HTTP utility for androidSomenath Mukhopadhyay
 
Java concurrency model - The Future Task
Java concurrency model - The Future TaskJava concurrency model - The Future Task
Java concurrency model - The Future TaskSomenath Mukhopadhyay
 
Memory layout in C++ vis a-vis polymorphism and padding bits
Memory layout in C++ vis a-vis polymorphism and padding bitsMemory layout in C++ vis a-vis polymorphism and padding bits
Memory layout in C++ vis a-vis polymorphism and padding bitsSomenath Mukhopadhyay
 
Developing an Android REST client to determine POI using asynctask and integr...
Developing an Android REST client to determine POI using asynctask and integr...Developing an Android REST client to determine POI using asynctask and integr...
Developing an Android REST client to determine POI using asynctask and integr...Somenath Mukhopadhyay
 
How to create your own background for google docs
How to create your own background for google docsHow to create your own background for google docs
How to create your own background for google docsSomenath Mukhopadhyay
 
The Designing of a Software System from scratch with the help of OOAD & UML -...
The Designing of a Software System from scratch with the help of OOAD & UML -...The Designing of a Software System from scratch with the help of OOAD & UML -...
The Designing of a Software System from scratch with the help of OOAD & UML -...Somenath Mukhopadhyay
 
Structural Relationship between Content Resolver and Content Provider of Andr...
Structural Relationship between Content Resolver and Content Provider of Andr...Structural Relationship between Content Resolver and Content Provider of Andr...
Structural Relationship between Content Resolver and Content Provider of Andr...Somenath Mukhopadhyay
 
Flow of events during Media Player creation in Android
Flow of events during Media Player creation in AndroidFlow of events during Media Player creation in Android
Flow of events during Media Player creation in AndroidSomenath Mukhopadhyay
 
Implementation of a state machine for a longrunning background task in androi...
Implementation of a state machine for a longrunning background task in androi...Implementation of a state machine for a longrunning background task in androi...
Implementation of a state machine for a longrunning background task in androi...Somenath Mukhopadhyay
 
Tackling circular dependency in Java
Tackling circular dependency in JavaTackling circular dependency in Java
Tackling circular dependency in JavaSomenath Mukhopadhyay
 
Implementation of composite design pattern in android view and widgets
Implementation of composite design pattern in android view and widgetsImplementation of composite design pattern in android view and widgets
Implementation of composite design pattern in android view and widgetsSomenath Mukhopadhyay
 
Exception Handling in the C++ Constructor
Exception Handling in the C++ ConstructorException Handling in the C++ Constructor
Exception Handling in the C++ ConstructorSomenath Mukhopadhyay
 
Android Asynctask Internals vis-a-vis half-sync half-async design pattern
Android Asynctask Internals vis-a-vis half-sync half-async design patternAndroid Asynctask Internals vis-a-vis half-sync half-async design pattern
Android Asynctask Internals vis-a-vis half-sync half-async design patternSomenath Mukhopadhyay
 

Plus de Somenath Mukhopadhyay (20)

Significance of private inheritance in C++...
Significance of private inheritance in C++...Significance of private inheritance in C++...
Significance of private inheritance in C++...
 
Arranging the words of a text lexicographically trie
Arranging the words of a text lexicographically   trieArranging the words of a text lexicographically   trie
Arranging the words of a text lexicographically trie
 
Generic asynchronous HTTP utility for android
Generic asynchronous HTTP utility for androidGeneric asynchronous HTTP utility for android
Generic asynchronous HTTP utility for android
 
Copy on write
Copy on writeCopy on write
Copy on write
 
Java concurrency model - The Future Task
Java concurrency model - The Future TaskJava concurrency model - The Future Task
Java concurrency model - The Future Task
 
Memory layout in C++ vis a-vis polymorphism and padding bits
Memory layout in C++ vis a-vis polymorphism and padding bitsMemory layout in C++ vis a-vis polymorphism and padding bits
Memory layout in C++ vis a-vis polymorphism and padding bits
 
Developing an Android REST client to determine POI using asynctask and integr...
Developing an Android REST client to determine POI using asynctask and integr...Developing an Android REST client to determine POI using asynctask and integr...
Developing an Android REST client to determine POI using asynctask and integr...
 
Observer pattern
Observer patternObserver pattern
Observer pattern
 
Uml training
Uml trainingUml training
Uml training
 
How to create your own background for google docs
How to create your own background for google docsHow to create your own background for google docs
How to create your own background for google docs
 
The Designing of a Software System from scratch with the help of OOAD & UML -...
The Designing of a Software System from scratch with the help of OOAD & UML -...The Designing of a Software System from scratch with the help of OOAD & UML -...
The Designing of a Software System from scratch with the help of OOAD & UML -...
 
Structural Relationship between Content Resolver and Content Provider of Andr...
Structural Relationship between Content Resolver and Content Provider of Andr...Structural Relationship between Content Resolver and Content Provider of Andr...
Structural Relationship between Content Resolver and Content Provider of Andr...
 
Flow of events during Media Player creation in Android
Flow of events during Media Player creation in AndroidFlow of events during Media Player creation in Android
Flow of events during Media Player creation in Android
 
Implementation of a state machine for a longrunning background task in androi...
Implementation of a state machine for a longrunning background task in androi...Implementation of a state machine for a longrunning background task in androi...
Implementation of a state machine for a longrunning background task in androi...
 
Tackling circular dependency in Java
Tackling circular dependency in JavaTackling circular dependency in Java
Tackling circular dependency in Java
 
Implementation of composite design pattern in android view and widgets
Implementation of composite design pattern in android view and widgetsImplementation of composite design pattern in android view and widgets
Implementation of composite design pattern in android view and widgets
 
Exception Handling in the C++ Constructor
Exception Handling in the C++ ConstructorException Handling in the C++ Constructor
Exception Handling in the C++ Constructor
 
Android services internals
Android services internalsAndroid services internals
Android services internals
 
Android Asynctask Internals vis-a-vis half-sync half-async design pattern
Android Asynctask Internals vis-a-vis half-sync half-async design patternAndroid Asynctask Internals vis-a-vis half-sync half-async design pattern
Android Asynctask Internals vis-a-vis half-sync half-async design pattern
 
Composite Pattern
Composite PatternComposite Pattern
Composite Pattern
 

Dernier

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 

Dernier (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 

Active object of Symbian in the lights of client server architecture

  • 1. Active Objects of Symbian in the lights of Client-Server architecture by Somenath Mukhopadhyay som.mukhopadhyay@gmail.com 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
  • 2. 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>
  • 3. // 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);
  • 4. } 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 {
  • 5. 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();
  • 6. 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); }
  • 7. // 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()
  • 8. { 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
  • 9. 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()
  • 10. { 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>
  • 11. _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
  • 12. 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;
  • 13. }; #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();
  • 14. } 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. 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"
  • 15. // 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.
  • 16. */ 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>
  • 17. //#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:privateEB0B3448ActiveObjectTest.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); }
  • 18. // ----------------------------------------------------------------------------// 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));
  • 19. 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; } }
  • 20. // ----------------------------------------------------------------------------// 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:
  • 21. 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 2. 3. 4. 5. 6. command The Observer's callback function is called to notify the UI about this state The engine delegates the task to a background server application The server finishes this task asynchronously and signals the Active Scheduler of the UI application through inter process communication The Active Scheduler of the UI application calls the RunL() function 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.
  • 22. 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. Reference: The book for Accredited Symbian Developer exam and the associated code