|
1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Implementation of Device Service Object |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <config.h> |
|
20 #include "ServiceObject.h" |
|
21 #include "Device.h" |
|
22 #include "DeviceBinding.h" |
|
23 #include "DeviceLiwInterface.h" |
|
24 #include "DeviceLiwResult.h" |
|
25 #include "DeviceLiwPeer.h" |
|
26 #include <PropertyNameArray.h> |
|
27 |
|
28 using namespace KJS; |
|
29 const ClassInfo ServiceObject::info = { "ServiceObject", 0, 0, 0 }; |
|
30 _LIT8( KWildChar, "*" ); |
|
31 // ============================ MEMBER FUNCTIONS =============================== |
|
32 |
|
33 /* |
|
34 @begin ServiceObjectTable 1 |
|
35 close ServiceObject::close DontDelete|Function 1 |
|
36 @end |
|
37 */ |
|
38 // ---------------------------------------------------------------------------- |
|
39 // ServiceObject::ServiceObject |
|
40 // |
|
41 // |
|
42 // |
|
43 // ---------------------------------------------------------------------------- |
|
44 ServiceObject::ServiceObject( |
|
45 ExecState* exec, |
|
46 HBufC8* svcName, |
|
47 MDeviceBinding* deviceBinding) |
|
48 : JSObject( exec->lexicalInterpreter()->builtinObjectPrototype() ) |
|
49 { |
|
50 m_privateData = new ServiceObjectPrivate(svcName, deviceBinding); |
|
51 if (m_privateData && m_privateData->m_deviceBinding) |
|
52 { |
|
53 m_valid = true; |
|
54 // protect this object |
|
55 KJS::Collector::protect(this); |
|
56 } |
|
57 else |
|
58 { |
|
59 m_valid = false; |
|
60 } |
|
61 } |
|
62 |
|
63 |
|
64 // ---------------------------------------------------------------------------- |
|
65 // ServiceObject::~ServiceObject |
|
66 // |
|
67 // |
|
68 // |
|
69 // ---------------------------------------------------------------------------- |
|
70 ServiceObject::~ServiceObject() |
|
71 { |
|
72 // only can be called by garbage collection after the |
|
73 // ServiceObject::Close() was called |
|
74 } |
|
75 |
|
76 // ---------------------------------------------------------------------------- |
|
77 // ServiceObject::Close |
|
78 // |
|
79 // ---------------------------------------------------------------------------- |
|
80 void ServiceObject::Close( ExecState* exec, bool unmark ) |
|
81 { |
|
82 // avoid double close |
|
83 if(!m_valid) |
|
84 { |
|
85 if(unmark) |
|
86 { |
|
87 // unprotect this to allow the garbage collection to release this jsobject |
|
88 KJS::Collector::unprotect(this); |
|
89 } |
|
90 return; |
|
91 } |
|
92 |
|
93 // set isClosing flag to true |
|
94 m_privateData->isClosing = true; |
|
95 |
|
96 if ( exec ) |
|
97 { |
|
98 PropertyNameArray propertyNames; |
|
99 this->getPropertyNames( exec, propertyNames ); |
|
100 unsigned size = static_cast<unsigned>(propertyNames.size()); |
|
101 |
|
102 for (unsigned i = 0; i < size; i++) |
|
103 { |
|
104 JSValue * jsvalue = this->get( exec, propertyNames[i] ); |
|
105 if(jsvalue->isObject()) |
|
106 { |
|
107 JSObject * prop = jsvalue->toObject( exec ); |
|
108 if (prop->inherits( &DeviceLiwInterface::info )) |
|
109 { |
|
110 (static_cast<DeviceLiwInterface*>(prop))->Close(exec); |
|
111 } |
|
112 } |
|
113 } |
|
114 } |
|
115 |
|
116 delete m_privateData; |
|
117 m_privateData = NULL; |
|
118 m_valid = false; |
|
119 |
|
120 if(unmark) |
|
121 { |
|
122 // unprotect this to allow the garbage collection to release this jsobject |
|
123 KJS::Collector::unprotect(this); |
|
124 } |
|
125 } |
|
126 |
|
127 // ---------------------------------------------------------------------------- |
|
128 // ServiceObject::toString |
|
129 // |
|
130 // |
|
131 // |
|
132 // ---------------------------------------------------------------------------- |
|
133 UString ServiceObject::toString( ExecState* exec ) const |
|
134 { |
|
135 return "[object ServiceObject]"; |
|
136 } |
|
137 |
|
138 |
|
139 // ---------------------------------------------------------------------------- |
|
140 // ServiceObject::getOwnPropertySlot |
|
141 // |
|
142 // |
|
143 // |
|
144 // ---------------------------------------------------------------------------- |
|
145 bool ServiceObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
|
146 { |
|
147 // When the ServiceObject is valid, the check order is |
|
148 // ServiceObject table => own property => prototype property |
|
149 // When the ServiceObject is invalid (after close), the check order is |
|
150 // close function in table => prototype property |
|
151 |
|
152 // 1. when it is valid |
|
153 if(m_valid) |
|
154 { |
|
155 // 1.1 check ServiceObject table |
|
156 const HashEntry* entry = Lookup::findEntry(&ServiceObjectTable, propertyName); |
|
157 if (entry) |
|
158 { |
|
159 slot.setStaticEntry(this, entry, staticValueGetter<ServiceObject>); |
|
160 return true; |
|
161 } |
|
162 |
|
163 // 1.2 check own property |
|
164 m_privateData->m_propName = propertyName; |
|
165 JSValue* val = getDirect( propertyName ); |
|
166 |
|
167 // if the property is an interface and interface is closed |
|
168 bool need_recreate = false; |
|
169 if ( val && val->isObject() && |
|
170 val->toObject(exec)->inherits( &KJS::DeviceLiwInterface::info ) ) |
|
171 { |
|
172 DeviceLiwInterface* interface = static_cast<DeviceLiwInterface*>(val); |
|
173 if ( !interface->isValid() && !m_privateData->isClosing) |
|
174 { |
|
175 need_recreate = true; |
|
176 } |
|
177 } |
|
178 |
|
179 if ( !val || need_recreate ) |
|
180 { |
|
181 if ( !val ) |
|
182 { |
|
183 // 1.3 check prototypes |
|
184 JSObject *proto = static_cast<JSObject *>(this->prototype()); |
|
185 |
|
186 while (!proto->isNull() && proto->isObject()) { |
|
187 if (proto->getOwnPropertySlot(exec, propertyName, slot)) |
|
188 return true; |
|
189 |
|
190 proto = static_cast<JSObject *>(proto->prototype()); |
|
191 } |
|
192 } |
|
193 |
|
194 // Store the interface in the object so we get the same one each time. |
|
195 JSValue* resultVal = m_privateData->m_deviceBinding->CreateInterface( |
|
196 exec, m_privateData->m_svcName, m_privateData->m_propName ); |
|
197 |
|
198 if ( resultVal->type() == UndefinedType || exec->hadException() ) |
|
199 return false; |
|
200 else |
|
201 { |
|
202 JSValue* s = resultVal->toObject(exec)->get( exec, m_privateData->m_propName ); |
|
203 this->putDirect( propertyName, s, DontDelete|ReadOnly ); |
|
204 } |
|
205 |
|
206 // clean the DeviceLiwResult which is useless |
|
207 if(resultVal->isObject()) |
|
208 { |
|
209 JSObject * jsobj = resultVal->toObject( exec ); |
|
210 if(jsobj->inherits( &KJS::DeviceLiwResult::info )) |
|
211 { |
|
212 DeviceLiwResult* result = static_cast<DeviceLiwResult*>(jsobj); |
|
213 result->quickClose(); |
|
214 } |
|
215 } |
|
216 } |
|
217 return JSObject::getOwnPropertySlot(exec, propertyName, slot); |
|
218 } |
|
219 // 2. when it is invalid |
|
220 else |
|
221 { |
|
222 // 2.1 check close function |
|
223 if (propertyName == "close") |
|
224 { |
|
225 const HashEntry* entry = Lookup::findEntry(&ServiceObjectTable, propertyName); |
|
226 if (entry) |
|
227 { |
|
228 slot.setStaticEntry(this, entry, staticValueGetter<ServiceObject>); |
|
229 return true; |
|
230 } |
|
231 } |
|
232 |
|
233 // 2.2 check prototypes |
|
234 JSObject *proto = static_cast<JSObject *>(this->prototype()); |
|
235 while (!proto->isNull() && proto->isObject()) |
|
236 { |
|
237 if (proto->getOwnPropertySlot(exec, propertyName, slot)) |
|
238 return true; |
|
239 |
|
240 proto = static_cast<JSObject *>(proto->prototype()); |
|
241 } |
|
242 } |
|
243 |
|
244 return false; |
|
245 } |
|
246 |
|
247 // ---------------------------------------------------------------------------- |
|
248 // ServiceObject::get |
|
249 // |
|
250 // |
|
251 // |
|
252 // ---------------------------------------------------------------------------- |
|
253 JSValue* ServiceObject::getValueProperty(KJS::ExecState* exec, int token) const |
|
254 { |
|
255 if (token == close) |
|
256 { |
|
257 return new ServiceObjectFunc( exec, token ); |
|
258 } |
|
259 if(m_valid) |
|
260 return getDirect(m_privateData->m_propName); |
|
261 else |
|
262 return jsUndefined(); |
|
263 } |
|
264 |
|
265 // ---------------------------------------------------------------------------- |
|
266 // ServiceObject::IsRunningCallBack |
|
267 // |
|
268 // |
|
269 // |
|
270 // ---------------------------------------------------------------------------- |
|
271 TBool ServiceObject::IsRunningCallBack(ExecState *exec) |
|
272 { |
|
273 PropertyNameArray propertyNames; |
|
274 this->getPropertyNames( exec, propertyNames ); |
|
275 unsigned size = static_cast<unsigned>(propertyNames.size()); |
|
276 |
|
277 for (unsigned i = 0; i < size; i++) |
|
278 { |
|
279 JSValue * jsvalue = this->get( exec, propertyNames[i] ); |
|
280 if(jsvalue->isObject()) |
|
281 { |
|
282 JSObject * prop = jsvalue->toObject( exec ); |
|
283 if (prop->inherits( &DeviceLiwInterface::info )) |
|
284 { |
|
285 if((static_cast<DeviceLiwInterface*>(prop))->IsRunningCallBack()) |
|
286 { |
|
287 return ETrue; |
|
288 } |
|
289 } |
|
290 } |
|
291 } |
|
292 return EFalse; |
|
293 } |
|
294 |
|
295 ServiceObjectFunc::ServiceObjectFunc( ExecState* exec, int token ) |
|
296 : JSObject( exec->lexicalInterpreter()->builtinObjectPrototype() ), |
|
297 m_func( token ) |
|
298 { |
|
299 } |
|
300 |
|
301 JSValue* ServiceObjectFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) |
|
302 { |
|
303 JSValue* ret = jsUndefined(); |
|
304 if (!thisObj->inherits( &KJS::ServiceObject::info ) ) |
|
305 { |
|
306 return throwError(exec, GeneralError); |
|
307 } |
|
308 ServiceObject* so = static_cast<ServiceObject*>(thisObj); |
|
309 |
|
310 if(!so->isValid()) |
|
311 return ret; |
|
312 |
|
313 if ( m_func == ServiceObject::close ) |
|
314 { |
|
315 // the close function cann't be called in the callback function |
|
316 if(so->IsRunningCallBack(exec)) |
|
317 { |
|
318 return throwError(exec, GeneralError, "Can not close service object in callback function."); |
|
319 } |
|
320 so->Close( exec, false ); |
|
321 } |
|
322 return ret; |
|
323 } |
|
324 |
|
325 // --------------------------------------------------------------------------- |
|
326 // DeviceLiwMapPrivate constructor |
|
327 // |
|
328 // --------------------------------------------------------------------------- |
|
329 ServiceObjectPrivate::ServiceObjectPrivate(HBufC8* svcName, MDeviceBinding* deviceBinding ) |
|
330 { |
|
331 m_svcName = svcName; |
|
332 m_deviceBinding = deviceBinding; |
|
333 isClosing = false; |
|
334 } |
|
335 |
|
336 // --------------------------------------------------------------------------- |
|
337 // DeviceLiwMapPrivate::Close |
|
338 // |
|
339 // --------------------------------------------------------------------------- |
|
340 void ServiceObjectPrivate::Close() |
|
341 { |
|
342 m_deviceBinding->UnloadServiceProvider(KWildChar(), m_svcName->Des()); |
|
343 m_deviceBinding = NULL; |
|
344 |
|
345 delete m_svcName; |
|
346 m_svcName = NULL; |
|
347 } |
|
348 |
|
349 //END OF FILE |