Week 23 contribution of PDK documentation content. See release notes for details. Fixes bugs Bug 2714, Bug 462.
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License
"Eclipse Public License v1.0" which accompanies this distribution,
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
Nokia Corporation - initial contribution.
Contributors:
-->
<!DOCTYPE concept
PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-FAE3F35C-04C1-5CF4-8090-9DF58AD1C02A" xml:lang="en"><title>How
to implement a server interface with subsessions</title><shortdesc>Provides code snippets to help you to implement a server interface
with subsessions.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>A server side subsession is represented by an instance of a class derived
from <codeph>CObject</codeph>. </p>
<p>The following sections refer to an example server, known as the count server.
The code fragments are taken from the example that can be found at <filepath>...\examples\Base\IPC\ClientServer\complex</filepath>. </p>
<p>In the example, a server side session is represented by the <codeph>CSession2</codeph> derived
class <codeph>CCountSession</codeph>. The server session can have any number
of subsessions, referred to as counters in the example. The subsessions are
instances of the <codeph>CCountSubSession</codeph> class and these are derived
from <codeph>CObject</codeph>. </p>
<p>Unlike the implementation for a simple server interface, as shown in the
example that can be found at <filepath>...\examples\Base\IPC\ClientServer\simple</filepath>,
the functions to service client requests, e.g. <codeph>Increase()</codeph>,
are in class <codeph>CCountSubSession</codeph> rather than <codeph>CCountSession</codeph>. </p>
<p>The important points to note are: </p>
<ul>
<li id="GUID-98D487B0-ECFF-5A83-BEF0-C66475836888"><p>the <codeph>CCountSession</codeph> class
contains the object container for all the subsession objects which belong
to this session. </p> </li>
<li id="GUID-BCE1BF57-FC9E-58CF-9E77-1AD48632DFC0"><p>the <codeph>CCountServer</codeph> class
contains the <i>one and only</i> object container index through which all
object containers within the server are produced. </p> </li>
<li id="GUID-78880ABD-904A-5D3C-988A-646CE2998050"><p>the <codeph>CCountSession</codeph> class
contains an object index through which a handle number can be generated for
the subsession. </p> </li>
</ul>
<section id="GUID-D49A6975-81B7-4BEE-8F46-C0F850CB4974"><title>Server session representation</title> <p>The <codeph>CCountSession</codeph> class
is defined as: </p> <codeblock id="GUID-F8FED60B-823A-5965-97F2-0BF6EC24620D" xml:space="preserve">class CCountSession : public CSession2
{
public:
// Create the session
static CCountSession* NewL();
public:
// Constructor
CCountSession();
// Called by client/server framework after
// session has been successfully created
void CreateL();
// Service request
void ServiceL(const RMessage2& aMessage);
void DispatchMessageL(const RMessage2& aMessage);
// Creates new subsession
void NewCounterL(const RMessage2& aMessage);
// Closes the session
void CloseSession();
// Gets the number of resources (i.e. CCountSubSession objects)
void NumResources(const RMessage2& aMessage);
// Utility to return the CCountSubSession (subsession) object
CCountSubSession* CounterFromHandle(const RMessage2& aMessage,TInt aHandle);
// Delete the subsession object through its handle.
void DeleteCounter(TInt aHandle);
// Gets the number of server-side subsession objects.
TInt CountResources();
// Panics client
void PanicClient(const RMessage2& aMessage,TInt aPanic) const;
private:
// Object container for this session.
CObjectCon *iContainer;
// Object index which stores objects
// (CCountSubSession instances) for this session.
CObjectIx* iCountersObjectIndex;
// Total number of resources. In this example
// a resource is just the number of CCountSubSession objects.
TInt iResourceCount;
};
</codeblock> <p><b>Notes</b> </p> <ul>
<li id="GUID-DD9D1AE3-315E-5ADF-A251-5F9BAAF24EED"><p>The data member <codeph>iCountersObjectIndex</codeph> is
a pointer to an <i>object index</i>. Once a subsession object has been created
and stored in its <i>object container</i>, it is then added to the <i>object
index</i> to generate a unique handle number for the counter (<keyword>subsession
object</keyword>). </p> </li>
<li id="GUID-0AE88EE6-1E87-5699-92FF-F55225320DF8"><p>The <codeph>CCounterFromHandle()</codeph> function
returns the subsession object corresponding to a specified handle number. </p> </li>
<li id="GUID-64A79B53-B798-50DA-B4F5-0DA5881F964E"><p>The <codeph>NewCounterL()</codeph> function
creates a new subsession object. </p> </li>
<li id="GUID-C9C9619D-EE0D-5B3F-B51C-354C9D7066D1"><p>The <codeph>DeleteCounter()</codeph> function
deletes a subsession object. This is called when the client program requests
to close a subsession. </p> </li>
</ul> </section>
<section id="GUID-CB7E6555-DE45-426A-B816-3736E72904FE"><title>Subsession object representation</title> <p>The <codeph>CCountSubSession</codeph> class
which represents the subsession is defined as: </p> <codeblock id="GUID-A91DD957-4A51-58E1-B0A0-843DAF9FF483" xml:space="preserve">class CCountSubSession : public CObject
{
public:
// creates a new CCountSubSession object.
static CCountSubSession* NewL(CCountSession* aSession);
public:
CCountSubSession(CCountSession* aSession);
void ConstructL(CCountSession* aSession);
void SetFromStringL(const RMessage2& aMessage);
void Increase();
void IncreaseBy(const RMessage2& aMessage);
void Decrease();
void DecreaseBy(const RMessage2& aMessage);
void Reset();
void CounterValue(const RMessage2& aMessage);
protected:
// The session that owns this CCountSubSession object.
CCountSession* iSession;
private:
// The counter value
TInt iCount;
};</codeblock> <p><b>Notes</b> </p> <ul>
<li id="GUID-04B1ACC9-AA68-56C7-B42A-DC7DAA0749B0"><p>The <codeph>NewL()</codeph> function
creates and returns a new instance of the subsession object. This is called
when the client requests the creation of a new subsession. </p> </li>
<li id="GUID-8BF98800-E081-5120-914F-60AE09C1A70A"><p>The <i>message service
functions</i> <codeph>Increase()</codeph>, <codeph>IncreaseBy()</codeph> etc.
respond appropriately to client requests. </p> </li>
</ul> </section>
<section id="GUID-1031D378-90C7-42A4-B1E5-C8BA10145B86"><title>Implementing a subsession request</title> <p>Subsession requests
are handled in a similar way to session requests. </p> <p>A subsession request
is initially handled by the associated session, i.e. it is passed to the appropriate <codeph>CSession2::ServiceL()</codeph>. </p> <codeblock id="GUID-AE6EDE6F-54B2-56DC-A793-A6AE630A223A" xml:space="preserve">void CCountSession::ServiceL(const RMessage2& aMessage)
{
TRAPD(err,DispatchMessageL(aMessage));
aMessage.Complete(err);
}
</codeblock> <p>The appropriate service function is called via <codeph>DispatchMessageL()</codeph> and
the asynchronous request is completed with <codeph>aMessage.Complete()</codeph>.
This applies to messages targeted at sessions and subsessions. </p> <p><b>DispatchMessageL()</b> </p> <p>The following code fragment shows important parts of this function: </p> <codeblock id="GUID-EB719B38-AA2C-5C19-B7BE-2332BD853057" xml:space="preserve">void CCountSession::DispatchMessageL(const RMessage2& aMessage)
{
// First check for session-relative requests
switch (aMessage.Function())
{
case ECountServCreateSubSession:// Request to create a subsession
NewCounterL(aMessage);
return;
case ECountServCloseSession: // Request to delete a subsession
CloseSession();
return;
...
}
...
// Must be a subsession request
// Find out Which subsession and
// forward the request to it.
CCountSubSession* counter=CounterFromHandle(aMessage,aMessage.Int3())
switch (aMessage.Function())
{
...
case ECountServValue:
counter->CounterValue(aMessage);
return;
default:
PanicClient(EBadRequest);
return;
}
}</codeblock> <codeblock id="GUID-F0C7D2A2-FC3E-5CC0-A776-7D7B7047D758" xml:space="preserve">CCountSubSession* CCountSession::CounterFromHandle(const RMessage2& aMessage,TInt aHandle)
{
CCountSubSession* counter = (CCountSubSession*)iCountersObjectIndex->At(aHandle);
if (counter == NULL)
{
PanicClient(aMessage, EBadSubsessionHandle);
}
return counter;
}
</codeblock> <p><b>Notes</b> </p> <ul>
<li id="GUID-55B94E1E-C761-5D39-9EBF-9A2E600E26A3"><p>The function first checks
for messages which are specific to a session and this includes those requests
to create and delete a subsession. </p> </li>
<li id="GUID-D65039AA-E45E-5CA6-8A25-E8F3680CDA72"><p>After deciding that
messages must be forwarded to a subsession, the function uses the handle number
supplied through the fourth parameter in the message argument array and the <codeph>CounterFromHandle()</codeph> function
to retrieve the appropriate subsession object. </p> </li>
<li id="GUID-54BC7669-BBA9-5134-857A-8F4060059EB7"><p>It then invokes the
appropriate message service function on that subsession to deal with the client
request. </p> </li>
<li id="GUID-7CA3D0C0-E7DB-58FC-A89D-2584C25A7685"><p>The <codeph>At()</codeph> function
is provided by the <codeph>CObject</codeph> base class. </p> </li>
</ul> </section>
</conbody></concept>