|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF" xml:lang="en"><title>Using |
|
13 Publish and Subscribe</title><shortdesc>This topic explains the operations that can be performed using |
|
14 publish and subscribe.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
15 <ul> |
|
16 <li id="GUID-AE4CAAA9-9EB2-5AA0-ACB9-073EAAA9D2C1"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-383A6127-FCE0-5B0E-BD54-3AAFEB097AC9">Creating and closing a handle to a property</xref> </p> </li> |
|
17 <li id="GUID-3F0622EC-8490-585A-8CA8-09A3925E842E"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-75BCC783-8DA2-519F-9E4A-B597BDC90E79">Defining a property</xref> </p> </li> |
|
18 <li id="GUID-D6C38BDD-02CD-5D9F-8872-DD621D58DB85"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-D942B400-37F8-5C02-AC95-2BD195D3348D">Deleting a property</xref> </p> </li> |
|
19 <li id="GUID-ED1DE72F-9111-51A5-9AB2-D7112D947465"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-3B2B63B8-EB2A-5845-A738-A10012A7C896">Publishing a property value</xref> </p> </li> |
|
20 <li id="GUID-360F7C12-4909-52EE-9468-E40A3ABC944A"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-CD731DD7-E833-5C67-9B90-0357C9552450">Retrieving a property value</xref> </p> </li> |
|
21 <li id="GUID-57301501-34C1-5BE1-9AAB-36F97DBCF5C0"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-A17955E9-FC4C-5FF9-8CC4-2425931E1DEB">Subscribing to, and unsubscribing from, a property</xref> </p> </li> |
|
22 <li id="GUID-AAA0B4BB-4B01-5F5E-8617-6D02B36DCEF2"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-EF683969-CED9-5986-938D-3D887E3B39BD">Usage patterns</xref> </p> </li> |
|
23 <li id="GUID-E2D3A0BE-1FD9-5B56-928A-4265940E0DEA"><p> <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-2B022BE9-2004-54E8-962E-5AB38DDC4222">Making efficient use of the user side API</xref> </p> </li> |
|
24 </ul> |
|
25 <section id="GUID-383A6127-FCE0-5B0E-BD54-3AAFEB097AC9"><title>Creating and |
|
26 closing a handle to a property</title> <p>Some property operations require |
|
27 a reference to the property to be established first. This is done using the <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-3F65DD85-6061-3370-9618-ECC0400323D1"><apiname>RProperty::Attach()</apiname></xref> member |
|
28 function. After a call to this function, the <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita"><apiname>RProperty</apiname></xref> object |
|
29 acts like a standard handle to a kernel resource. When this handle is no longer |
|
30 required, it can be released in the standard way by calling the inherited <xref href="GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB.dita#GUID-727D2B62-09A9-3CBC-AB6F-591E52EC68EB/GUID-4B2775FD-AB61-3850-86C5-780CE8C97573"><apiname>RHandleBase::Close()</apiname></xref> member |
|
31 function. </p> <p>Note that releasing the handle does not cause the property |
|
32 to disappear. This only happens if the property is deleted. </p> <p>Note also |
|
33 that it is quite legitimate to attach to a property that has not been defined, |
|
34 and in this case no error will be returned either. This enables the lazy definition |
|
35 of properties as used in some of the usage patterns. </p> <codeblock id="GUID-A836D288-8511-5CED-B3F9-42B60569EE27" xml:space="preserve">// attach to the ‘counter’ property |
|
36 RProperty counter; |
|
37 TInt r=counter.Attach(KMyPropertyCat,EMyPropertyName,EOwnerThread); |
|
38 User::LeaveIfError(r); |
|
39 |
|
40 // use the counter object... |
|
41 |
|
42 // when finished, release the handle |
|
43 counter.Close(); |
|
44 </codeblock> </section> |
|
45 <section id="GUID-75BCC783-8DA2-519F-9E4A-B597BDC90E79"><title>Defining a |
|
46 property</title> <p>A property is defined using the <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-58C54D2A-91E0-359B-AA31-69C6C4050173"><apiname>RProperty::Define()</apiname></xref> function, |
|
47 specifying the attributes of that property. </p> <p>A property does not need |
|
48 to be defined before it can be accessed. This supports programming patterns |
|
49 where both publishers and subscribers may define the property. Note, however |
|
50 that for security reasons, there are restrictions on the category that can |
|
51 be used when defining a property; see <xref href="GUID-DAF86036-CC40-5F26-9F15-2F2093F59C03.dita">security |
|
52 issues</xref> for more information. </p> <p>Once defined, a property persists |
|
53 in the kernel until the system reboots, or the property is explicitly deleted. |
|
54 Its lifetime is not tied to that of the thread or process that originally |
|
55 defined it. This means that, when defining a property, it is important to |
|
56 check the return code from the call <codeph>RProperty::Define()</codeph> to |
|
57 deal with the possibility that the property has previously been defined, but |
|
58 not deleted. </p> <p>The following code shows the definition of two properties: </p> <codeblock id="GUID-1F3E05DB-A34B-5D79-8512-52CAD86B0A2D" xml:space="preserve">enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
59 |
|
60 static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); |
|
61 static _LIT_SECURITY_POLICY_C1(KPowerMgmtPolicy,ECapabilityPowerMgmt); |
|
62 |
|
63 // define first property to be integer type |
|
64 TInt r=RProperty::Define(EMyPropertyCounter,RProperty::EInt,KAllowAllPolicy,KPowerMgmtPolicy); |
|
65 if (r!=KErrAlreadyExists) |
|
66 { |
|
67 User::LeaveIfError(r); |
|
68 } |
|
69 |
|
70 // define second property to be a byte array, allocating 100 bytes |
|
71 r=RProperty::Define(EMyPropertyName,RProperty::EByteArray,KAllowAllPolicy,KPowerMgmtPolicy,100); |
|
72 if (r!=KErrAlreadyExists) |
|
73 { |
|
74 User::LeaveIfError(r); |
|
75 } |
|
76 . . . |
|
77 </codeblock> <p>Once defined, a property value can change, but the property |
|
78 type cannot. Byte-array type properties can also change length provided the |
|
79 length does not exceed the maximum value of 512 bytes. The limit on the size |
|
80 of a property ensures some limit on RAM usage. </p> <p>The API allows byte-array |
|
81 and Unicode text type properties to be pre-allocated when they are defined. |
|
82 This means that the time taken to set the values is bounded. However, if the |
|
83 length of these property types subsequently increases, then memory allocation |
|
84 may take place, and no guarantees can then be made on the time taken to set |
|
85 them. </p> <p>There are further <xref href="GUID-DAF86036-CC40-5F26-9F15-2F2093F59C03.dita">security |
|
86 issues</xref> to be considered when defining a property. You need to provide |
|
87 two security policies - one to govern which processes can publish the property |
|
88 value, and the other to govern which processes can retrieve the property value. |
|
89 Security policies are instances of <xref href="GUID-81A285F6-3F87-3E77-9426-61BB16BC7109.dita"><apiname>TSecurityPolicy</apiname></xref> objects, |
|
90 although for efficiency reasons, you will almost always use the <codeph>_LIT_SECURITY_POLICY_...</codeph> macros |
|
91 to generate constant objects that behave like <codeph>TSecurityPolicy</codeph> objects. |
|
92 The API reference for <xref href="GUID-81A285F6-3F87-3E77-9426-61BB16BC7109.dita"><apiname>TSecurityPolicy</apiname></xref> provides far more |
|
93 detail on this. </p> <p>In this example, all processes will be allowed to |
|
94 retrieve the property value, but only those processes having the power management |
|
95 system capability (<xref href="GUID-76F4383B-4EA5-391A-A271-A8F65ED77EC0.dita"><apiname>ECapabilityPowerMgmt</apiname></xref>) will be allowed |
|
96 to publish the property value. </p> <p>Note that a process that defines a |
|
97 property does not have automatic rights of access to that property, other |
|
98 than to delete it. If the defining process also wishes to publish and/or subscribe |
|
99 to that property, then it must ensure that it satisfies the security policies |
|
100 that it itself has put in place when defining the property. </p> </section> |
|
101 <section id="GUID-D942B400-37F8-5C02-AC95-2BD195D3348D"><title>Deleting a |
|
102 property</title> <p>A defined property is deleted by calling <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-226BC411-A2D2-30D1-BD86-9DDBD855C1E4"><apiname>RProperty::Delete()</apiname></xref>. |
|
103 Any outstanding subscriptions for this property will complete with <xref href="GUID-5E653C17-372C-32E1-A1B2-9E69A9991C40.dita"><apiname>KErrNotFound</apiname></xref>. |
|
104 Only the process with the correct secure ID is allowed to delete it. </p> <p>For |
|
105 example, extending the code fragment introduced above: </p> <codeblock id="GUID-D4CC3017-D17D-5E7C-AC57-0DBD8B789349" xml:space="preserve">enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
106 |
|
107 // define first property to be integer type |
|
108 TInt r=RProperty::Define(EMyPropertyCounter,RProperty::EInt); |
|
109 if (r!=KErrAlreadyExists) |
|
110 { |
|
111 User::LeaveIfError(r); |
|
112 } |
|
113 |
|
114 // define second property to be a byte array, allocating 100 bytes |
|
115 r=RProperty::Define(EMyPropertyName,RProperty::EByteArray,100); |
|
116 if (r!=KErrAlreadyExists) |
|
117 { |
|
118 User::LeaveIfError(r); |
|
119 } |
|
120 . . . |
|
121 |
|
122 // much later on |
|
123 |
|
124 . . . |
|
125 // delete the ‘name’ property |
|
126 r=RProperty::Delete(EMyPropertyName); |
|
127 if (r!=KErrNotFound) |
|
128 { |
|
129 User::LeaveIfError(r); |
|
130 } |
|
131 </codeblock> </section> |
|
132 <section id="GUID-3B2B63B8-EB2A-5845-A738-A10012A7C896"><title>Publishing |
|
133 a property value</title> <p>A property is published using the <codeph>RProperty::Set()</codeph> family |
|
134 of functions. Properties can be published: </p> <ul> |
|
135 <li id="GUID-3A136703-587F-55B9-9EE6-EE512845956A"><p>using a previously attached <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita"><apiname>RProperty</apiname></xref> handle, </p> </li> |
|
136 </ul> <p>or </p> <ul> |
|
137 <li id="GUID-126B0DC1-D4FC-520C-9583-50E64CBC7B80"><p>by specifying the property |
|
138 category and key with the new value. </p> </li> |
|
139 </ul> <p>The former mode is guaranteed to have bounded execution time, suitable |
|
140 for high-priority, real-time tasks, except when publishing a byte-array property |
|
141 that requires the allocation of a larger space for the new value. </p> <p>The |
|
142 latter mode offers no real-time guarantees. </p> <p>Property values are written |
|
143 atomically. This means that it is not possible for threads reading a property |
|
144 to get a garbled value. </p> <p>All outstanding subscriptions for a property |
|
145 are completed when the value is published, even if it is exactly the same |
|
146 as the existing value. This means that a property can be used as a simple |
|
147 broadcast notification service. </p> <p>Publishing a property that is not |
|
148 defined is not necessarily a programming error. The <codeph>Set()</codeph> functions |
|
149 just return an error. If this is not expected for any particular usage, then |
|
150 the error must be checked and processed by the caller. </p> <p>See the code |
|
151 fragment in the section <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-CD731DD7-E833-5C67-9B90-0357C9552450">Retrieving |
|
152 a property value</xref> </p> </section> |
|
153 <section id="GUID-CD731DD7-E833-5C67-9B90-0357C9552450"><title>Retrieving |
|
154 a property value</title> <p>The current value of a property is read using |
|
155 the <codeph>RProperty::Get()</codeph> family of functions. Properties can |
|
156 be retrieved: </p> <ul> |
|
157 <li id="GUID-81AD34BF-9A45-5DEE-AD20-AA908F5BF94A"><p>using a previously attached <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita"><apiname>RProperty</apiname></xref> handle, </p> </li> |
|
158 </ul> <p>or </p> <ul> |
|
159 <li id="GUID-1163D9F2-BDEA-55E1-B6FB-D9A353F4D53E"><p>by specifying the property |
|
160 category and key with the new value. </p> </li> |
|
161 </ul> <p>The former mode is guaranteed to have bounded execution time, suitable |
|
162 for high-priority, real-time tasks. </p> <p>The latter mode offers no real-time |
|
163 guarantees. </p> <p>Property values are read atomically. This means that it |
|
164 is not possible for threads reading a property to get a garbled value. </p> <p>Retrieving |
|
165 a property that is not defined is not necessarily a programming error. The <codeph>Get()</codeph> functions |
|
166 just return an error. If this is not expected for any particular usage, then |
|
167 the error must be checked and processed by the caller. </p> <p>Integer properties |
|
168 must be accessed using the overloads that take an integer or integer reference |
|
169 value, whereas byte-array properties can be accessed using the overloads that |
|
170 take a descriptor reference. </p> <p>The following code fragment shows publication |
|
171 and retrieval of a property. Note that it uses the idea of attaching to a |
|
172 property. Note also that it contains a race condition, especially if another |
|
173 thread is executing the same sequence to increment the ‘counter’ value. </p> <codeblock id="GUID-27B8D567-DD92-5FD6-B2E3-AF343C1116B1" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
174 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
175 |
|
176 // attach to the ‘counter’ property |
|
177 RProperty counter; |
|
178 TInt r=counter.Attach(KMyPropertyCat,EMyPropertyCounter,EOwnerThread); |
|
179 User::LeaveIfError(r); |
|
180 |
|
181 // publish a new name value |
|
182 TFileName n; |
|
183 RProcess().Filename(n); |
|
184 r=RProperty::Set(KMyPropertyCat,EMyPropertyName,n); |
|
185 User::LeaveIfError(r); |
|
186 |
|
187 // retrieve the first 10 characters of the name value |
|
188 TBuf<10> name; |
|
189 r=RProperty::Get(KMyPropertyCat,EMyPropertyName,name); |
|
190 if (r!=KErrOverflow) |
|
191 { |
|
192 User::LeaveIfError(r); |
|
193 } |
|
194 |
|
195 // retrieve and publish a new value using the attached ‘counter’ property |
|
196 TInt count; |
|
197 r=counter.Get(count); |
|
198 if (r==KErrNone) |
|
199 { |
|
200 r=counter.Set(++count); |
|
201 } |
|
202 User::LeaveIfError(r); |
|
203 |
|
204 // when finised, release the handle |
|
205 counter.Close(); |
|
206 </codeblock> </section> |
|
207 <section id="GUID-A17955E9-FC4C-5FF9-8CC4-2425931E1DEB"><title>Subscribing |
|
208 to, and unsubscribing from, a property</title> <p>Subscribing to a property |
|
209 is the act of making an asynchronous request to be notified of a change to |
|
210 that property. </p> <p>A thread makes a request for notification of a change |
|
211 to a property by calling the <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-21A2FEB7-AAF1-3AC0-84B9-AB30E6CFFF99"><apiname>RProperty::Subscribe()</apiname></xref> member |
|
212 function on an already attached property object. Only one subscription request |
|
213 can be outstanding at any one time for a <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita"><apiname>RProperty</apiname></xref> instance. </p> <p>An |
|
214 outstanding subscription request can be cancelled by calling the <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-326D75D3-9D54-3BD2-8B78-FAD1EEA1A1A5"><apiname>RProperty::Cancel()</apiname></xref> member |
|
215 function. This is unsubscribing from the property. </p> <p>Subscribing to |
|
216 a property is a single request to be notified when the property is next updated, |
|
217 it does not generate an ongoing sequence of notifications for every change |
|
218 to that property's value. Neither does it provide the caller with the new |
|
219 value. In essence, the act of notification should be interpreted as “Property |
|
220 X has changed” rather than “Property X has changed to Y”. This means that |
|
221 the new value must be explicitly retrieved, if required. As a result, multiple |
|
222 updates may be collapsed into one notification, and subscribers may not have |
|
223 visibility of all intermediate values. </p> <p>This might appear to introduce |
|
224 a window of opportunity for a subscriber to be out of synchronisation with |
|
225 the property value – in particular, if the property is updated again before |
|
226 the subscriber thread has had the chance to process the original notification. |
|
227 However, a simple programming pattern, outlined in the second example below |
|
228 ensures this does not happen. The principle is that, before dealing with a |
|
229 subscription completion event, an active object should re-issue the subscription |
|
230 request. </p> <p>Note that if the property has not been defined, then a subscription |
|
231 request does not complete until the property is subsequently defined and published. |
|
232 Note that the request will complete with <xref href="GUID-213DE05E-24F7-3E94-9B35-F4A72B3EBFD8.dita"><apiname>KErrPermissionDenied</apiname></xref> if |
|
233 the subscribing process does not have sufficient capability as defined by |
|
234 the <xref href="GUID-81A285F6-3F87-3E77-9426-61BB16BC7109.dita"><apiname>TSecurityPolicy</apiname></xref> object supplied by the process defining |
|
235 the property. </p> <p>If the property is already defined, then the request |
|
236 completes immediately with <xref href="GUID-213DE05E-24F7-3E94-9B35-F4A72B3EBFD8.dita"><apiname>KErrPermissionDenied</apiname></xref> if the |
|
237 subscribing process does not have sufficient capability. </p> <codeblock id="GUID-F8AB71E9-1EB4-5EFB-9D1F-38625F782BA6" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
238 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
239 |
|
240 // attach to the ‘counter’ property |
|
241 RProperty counter; |
|
242 TInt r=counter.Attach(KMyPropertyCat,EMyPropertyCounter,EOwnerThread); |
|
243 User::LeaveIfError(r); |
|
244 |
|
245 // wait for the previously attached ‘counter’ property to be updated |
|
246 TRequestStatus s; |
|
247 counter.Subscribe(s); |
|
248 User::WaitForRequest(s); |
|
249 |
|
250 // Notification complete, retrieve the counter value. |
|
251 TInt count; |
|
252 counter.Get(count); |
|
253 . . . |
|
254 </codeblock> <codeblock id="GUID-5E726809-0060-5E76-A0D5-4AE73155724A" xml:space="preserve">const TUid KMyPropertyCat={0x10012345}; |
|
255 enum TMyPropertyKeys={EMyPropertyCounter,EMyPropertyName}; |
|
256 |
|
257 // Active object that tracks changes to the ‘name’ property |
|
258 class CPropertyWatch : public CActive |
|
259 { |
|
260 enum {EPriority=0}; |
|
261 public: |
|
262 static CPropertyWatch* NewL(); |
|
263 private: |
|
264 CPropertyWatch(); |
|
265 void ConstructL(); |
|
266 ~CPropertyWatch(); |
|
267 void RunL(); |
|
268 void DoCancel(); |
|
269 private: |
|
270 RProperty iProperty; |
|
271 }; |
|
272 |
|
273 CPropertyWatch* CPropertyWatch::NewL() |
|
274 { |
|
275 CPropertyWatch* me=new(ELeave) CPropertyWatch; |
|
276 CleanupStack::PushL(me); |
|
277 me->ConstructL(); |
|
278 CleanupStack::Pop(me); |
|
279 return me; |
|
280 } |
|
281 |
|
282 CPropertyWatch::CPropertyWatch() |
|
283 :CActive(EPriority) |
|
284 {} |
|
285 |
|
286 void CPropertyWatch::ConstructL() |
|
287 { |
|
288 User::LeaveIfError(iProperty.Attach(KMyPropertyCat,KMyPropertyName)); |
|
289 CActiveScheduler::Add(this); |
|
290 // initial subscription and process current property value |
|
291 RunL(); |
|
292 } |
|
293 |
|
294 CPropertyWatch::~CPropertyWatch() |
|
295 { |
|
296 Cancel(); |
|
297 iProperty.Close(); |
|
298 } |
|
299 |
|
300 void CPropertyWatch::DoCancel() |
|
301 { |
|
302 iProperty.Cancel(); |
|
303 } |
|
304 |
|
305 void CPropertyWatch::RunL() |
|
306 { |
|
307 // resubscribe before processing new value to prevent missing updates |
|
308 iProperty.Subscribe(iStatus); |
|
309 SetActive(); |
|
310 |
|
311 // property updated, get new value |
|
312 TFileName n; |
|
313 if (iProperty.Get(n)==KErrNotFound) |
|
314 { |
|
315 // property deleted, do necessary actions here... |
|
316 NameDeleted(); |
|
317 } |
|
318 else |
|
319 { |
|
320 // use new value ... |
|
321 NameChanged(n); |
|
322 } |
|
323 } |
|
324 </codeblock> </section> |
|
325 <section id="GUID-EF683969-CED9-5986-938D-3D887E3B39BD"><title>Usage patterns</title> <p>There |
|
326 are three usage patterns that can easily be identified, labelled as: standard |
|
327 state, pure event distribution, and speculative publishing. </p> <p id="GUID-0DFB902E-FCE1-52CF-8523-C7AE7B6768CE"><b>Standard state</b> </p> <p>This |
|
328 pattern is used for events and state that are known to be used widely in the |
|
329 system. Examples of this might be battery level and signal strength, which |
|
330 are important in every phone. </p> <p>The publisher calls <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-58C54D2A-91E0-359B-AA31-69C6C4050173"><apiname>RProperty::Define()</apiname></xref> to |
|
331 create the appropriate property. For byte array or text properties, a size |
|
332 sufficient for all possible values should be reserved. An error of <xref href="GUID-D1D25122-F2B8-3C78-8599-84905BFD47B8.dita"><apiname>KErrAlreadyExists</apiname></xref> should |
|
333 be ignored. The publisher then publishes the property values as, and when, |
|
334 appropriate. If the <codeph>RProperty::Set()</codeph> call fails, this should |
|
335 be treated as a serious error, since it indicates that important system state |
|
336 is not getting through. Appropriate action might include panicking or rebooting |
|
337 the system. Subscribers will use <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-21A2FEB7-AAF1-3AC0-84B9-AB30E6CFFF99"><apiname>RProperty::Subscribe()</apiname></xref> to |
|
338 request notification, and <codeph>RProperty::Get()</codeph> to retrieve the |
|
339 property value on notification. </p> <p>The memory to store the property value |
|
340 will be permanently allocated, even if it turns out that no-one in the system |
|
341 needs that value. This does ensure that the value can always be published, |
|
342 even if the system is in an out of memory situation. For this reason, this |
|
343 approach should be limited to widely used and important state. The <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-01254366-696D-598F-9670-6A178F4E69F7">Speculative publishing</xref> pattern offers an approach for dealing with |
|
344 less important state. </p> <p id="GUID-F2A60E64-C279-5E08-8AA8-52DF1EEA32BD"><b>Pure event distribution</b> </p> <p>This |
|
345 pattern is used when events need to be distributed, not values. </p> <p>The |
|
346 publisher of the event simply uses an integer property, and calls RProperty::Set() |
|
347 with any value. Even if the value of the property is not changed by this operation, |
|
348 all subscribers will be notified that a Set() has occurred, and by implication |
|
349 that the related event has occurred. </p> <p>Subscribers will be able to detect |
|
350 that an event has occurred, but will get no other information. The minimum |
|
351 possible memory is wasted on storage for the dummy value. </p> <p id="GUID-01254366-696D-598F-9670-6A178F4E69F7"><b>Speculative publishing</b> </p> <p>This |
|
352 pattern is used when it is not known whether a value will be of interest to |
|
353 others or not. Unlike the <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-0DFB902E-FCE1-52CF-8523-C7AE7B6768CE">standard |
|
354 state</xref> pattern, the publisher of the event does not call <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-58C54D2A-91E0-359B-AA31-69C6C4050173"><apiname>RProperty::Define()</apiname></xref> to |
|
355 create the property. Instead, it simply calls <codeph>RProperty::Set()</codeph> as |
|
356 appropriate, and ignores any <xref href="GUID-5E653C17-372C-32E1-A1B2-9E69A9991C40.dita"><apiname>KErrNotFound</apiname></xref> error. </p> <p>When |
|
357 other code in the system, i.e. a potential subscriber, is interested in the |
|
358 state, it calls <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-58C54D2A-91E0-359B-AA31-69C6C4050173"><apiname>RProperty::Define()</apiname></xref> to create the property |
|
359 and allocate the memory for the value. An error of <xref href="GUID-D1D25122-F2B8-3C78-8599-84905BFD47B8.dita"><apiname>KErrAlreadyExists</apiname></xref> should |
|
360 be ignored, as this only indicates that some other code in the system is also |
|
361 interested in the value and has already created the property. </p> <p>The |
|
362 subscriber then calls <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-21A2FEB7-AAF1-3AC0-84B9-AB30E6CFFF99"><apiname>RProperty::Subscribe()</apiname></xref> and <codeph>RProperty::Get()</codeph> as |
|
363 usual to interact with the property. On the first <codeph>Get()</codeph>, |
|
364 the subscriber may retrieve the property default value (zero, or a zero length |
|
365 descriptor). This must be substituted with a sensible default value for the |
|
366 property in question. </p> <p>Using this pattern, no memory is wasted on properties |
|
367 that have no subscribers, while the publisher code is simpler as there is |
|
368 no need for configuration as to which properties to publish. </p> <p>The publisher, |
|
369 however, wastes some time attempting to publish unneeded values, but this |
|
370 should not be an issue unless the value is very frequently updated. </p> <p>Where |
|
371 events are published very infrequently, the subscriber could have a dummy |
|
372 value for a long time, until the next publish event updates the value. Often |
|
373 this is not a problem as a default value can be substituted. For example a |
|
374 full/empty indicator for a battery level, none for signal strength etc. This |
|
375 pattern is unlikely to be useful if there is no suitable default value. </p> </section> |
|
376 <section id="GUID-2B022BE9-2004-54E8-962E-5AB38DDC4222"><title>Making efficient |
|
377 use of the user side API</title> <p>While the Publish and Subscribe API, as |
|
378 represented by <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita"><apiname>RProperty</apiname></xref> is designed to be efficient, there |
|
379 are certain usage patterns that can improve performance. </p> <p><b>Use |
|
380 the attached version of the API calls if possible</b> </p> <p>If you intend |
|
381 to call <codeph>Set()</codeph> or <codeph>Get()</codeph> repeatedly, it is |
|
382 preferable to use the attached forms of the calls. The attached forms are |
|
383 the ones that do not take a UID/Key parameter, and that can only be called |
|
384 after calling <xref href="GUID-C4776034-D190-3FC4-AF45-C7F195093AC3.dita#GUID-C4776034-D190-3FC4-AF45-C7F195093AC3/GUID-3F65DD85-6061-3370-9618-ECC0400323D1"><apiname>RProperty::Attach()</apiname></xref>. The attached variants |
|
385 are constant time operations, and execute much faster than the corresponding |
|
386 unattached versions. </p> <p><b>Only |
|
387 preallocate space if the publishing is time critical</b> </p> <p>For byte-array |
|
388 and text properties, it is possible to pre-allocate space for the data. Doing |
|
389 this results in <codeph>Set()</codeph> operations that do not exceed the preallocated |
|
390 space, avoiding the need to do a memory allocation. However, if the data is |
|
391 shorter than the reserved space, the excess is wasted. Since <codeph>Set()</codeph> automatically |
|
392 extends the data area if needed, then the only reason to pre-allocate space |
|
393 is if the <codeph>Set()</codeph> operation has to be real-time, i.e. has to |
|
394 have known execution time. </p> <p><b>Always |
|
395 consider using Speculative Publishing</b> </p> <p>Even in situations where |
|
396 the <xref href="GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF.dita#GUID-FE910347-7CC1-5241-B443-88AD3F5A96EF/GUID-0DFB902E-FCE1-52CF-8523-C7AE7B6768CE">Standard |
|
397 State</xref> pattern may seem appropriate, speculative publishing may be a |
|
398 better choice, specially for low-level components that know little about how |
|
399 they are used or what the wider system configuration may be. The onus is then |
|
400 on the UI/Policy layer to ensure that the appropriate properties are defined |
|
401 early on in device boot according to policy rules it can define. This ensures |
|
402 that the policy layers in the system maintain control and can implement a |
|
403 wide variety of policies. </p> <p>Standard state is only relevant for properties |
|
404 that are essential to every Symbian device. Battery level probably falls into |
|
405 this category, signal strength may well not. </p> <p><b>Define the expected update frequency</b> </p> <p>When a property is changed, |
|
406 all subscribers are notified. This leads to their threads running to service |
|
407 the notification. If a property changes value frequently, it would be wasteful |
|
408 for subscribers to perform substantial processing for each notification. </p> <p>Take |
|
409 a property representing signal strength as an example. Potentially, this could |
|
410 be updated several times a second. If a change in value were only used to |
|
411 update the UI signal bar, it would not be harmful. However, if it were used |
|
412 by many entities for serious processing (e.g. polling for email, sending unsent |
|
413 SMSes, re-connecting to the internet), then such frequent updates would have |
|
414 a severe effect on battery life. </p> <p>Nevertheless, it is obviously desirable |
|
415 for many parts of a phone OS to know about the state of network coverage, |
|
416 and to take appropriate action. In cases like this, it may be worth the publisher |
|
417 defining multiple properties with associated update characteristics. For example, |
|
418 raw signal strength (updated > 1 time/sec), periodic signal strength (updated |
|
419 once every 10s) and network coverage (updated only when moving between some |
|
420 signal and none). Each subscriber can then monitor the appropriate notification |
|
421 and so reduce the number of threads that run when the underlying value changes. </p> </section> |
|
422 </conbody></concept> |