added virtual method NetObj::linkObjects for post-load object linking; added flags...
[public/netxms.git] / src / server / core / netobj.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: netobj.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Class names
27 */
28 static const TCHAR *s_className[]=
29 {
30 _T("Generic"), _T("Subnet"), _T("Node"), _T("Interface"),
31 _T("Network"), _T("Container"), _T("Zone"), _T("ServiceRoot"),
32 _T("Template"), _T("TemplateGroup"), _T("TemplateRoot"),
33 _T("NetworkService"), _T("VPNConnector"), _T("Condition"),
34 _T("Cluster"), _T("PolicyGroup"), _T("PolicyRoot"),
35 _T("AgentPolicy"), _T("AgentPolicyConfig"), _T("NetworkMapRoot"),
36 _T("NetworkMapGroup"), _T("NetworkMap"), _T("DashboardRoot"),
37 _T("Dashboard"), _T("ReportRoot"), _T("ReportGroup"), _T("Report"),
38 _T("BusinessServiceRoot"), _T("BusinessService"), _T("NodeLink"),
39 _T("ServiceCheck"), _T("MobileDevice"), _T("Rack"), _T("AccessPoint"),
40 _T("AgentPolicyLogParser"), _T("Chassis")
41 };
42
43 /**
44 * Default constructor
45 */
46 NetObj::NetObj()
47 {
48 int i;
49
50 m_id = 0;
51 m_dwRefCount = 0;
52 m_mutexProperties = MutexCreate();
53 m_mutexRefCount = MutexCreate();
54 m_mutexACL = MutexCreate();
55 m_rwlockParentList = RWLockCreate();
56 m_rwlockChildList = RWLockCreate();
57 m_status = STATUS_UNKNOWN;
58 m_name[0] = 0;
59 m_comments = NULL;
60 m_isModified = false;
61 m_isDeleted = false;
62 m_isHidden = false;
63 m_isSystem = false;
64 m_maintenanceMode = false;
65 m_maintenanceEventId = 0;
66 m_childList = new ObjectArray<NetObj>(0, 16, false);
67 m_parentList = new ObjectArray<NetObj>(4, 4, false);
68 m_accessList = new AccessList();
69 m_inheritAccessRights = true;
70 m_dwNumTrustedNodes = 0;
71 m_pdwTrustedNodes = NULL;
72 m_pollRequestor = NULL;
73 m_statusCalcAlg = SA_CALCULATE_DEFAULT;
74 m_statusPropAlg = SA_PROPAGATE_DEFAULT;
75 m_fixedStatus = STATUS_WARNING;
76 m_statusShift = 0;
77 m_statusSingleThreshold = 75;
78 m_dwTimeStamp = 0;
79 for(i = 0; i < 4; i++)
80 {
81 m_statusTranslation[i] = i + 1;
82 m_statusThresholds[i] = 80 - i * 20;
83 }
84 m_submapId = 0;
85 m_moduleData = NULL;
86 m_postalAddress = new PostalAddress();
87 m_dashboards = new IntegerArray<UINT32>();
88 }
89
90 /**
91 * Destructor
92 */
93 NetObj::~NetObj()
94 {
95 MutexDestroy(m_mutexProperties);
96 MutexDestroy(m_mutexRefCount);
97 MutexDestroy(m_mutexACL);
98 RWLockDestroy(m_rwlockParentList);
99 RWLockDestroy(m_rwlockChildList);
100 delete m_childList;
101 delete m_parentList;
102 delete m_accessList;
103 safe_free(m_pdwTrustedNodes);
104 safe_free(m_comments);
105 delete m_moduleData;
106 delete m_postalAddress;
107 delete m_dashboards;
108 }
109
110 /**
111 * Get class name for this object
112 */
113 const TCHAR *NetObj::getObjectClassName() const
114 {
115 int c = getObjectClass();
116 return ((c >= 0) && (c < sizeof(s_className) / sizeof(const TCHAR *))) ? s_className[c] : _T("Custom");
117 }
118
119 /**
120 * Get class name for given class ID
121 */
122 const TCHAR *NetObj::getObjectClassName(int objectClass)
123 {
124 return ((objectClass >= 0) && (objectClass < sizeof(s_className) / sizeof(const TCHAR *))) ? s_className[objectClass] : _T("Custom");
125 }
126
127 /**
128 * Create object from database data
129 */
130 bool NetObj::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
131 {
132 return false; // Abstract objects cannot be loaded from database
133 }
134
135 /**
136 * Link related objects after loading from database
137 */
138 void NetObj::linkObjects()
139 {
140 }
141
142 /**
143 * Save object to database
144 */
145 BOOL NetObj::saveToDatabase(DB_HANDLE hdb)
146 {
147 return FALSE; // Abstract objects cannot be saved to database
148 }
149
150 /**
151 * Parameters for DeleteModuleDataCallback and SaveModuleDataCallback
152 */
153 struct ModuleDataDatabaseCallbackParams
154 {
155 UINT32 id;
156 DB_HANDLE hdb;
157 };
158
159 /**
160 * Callback for deleting module data from database
161 */
162 static EnumerationCallbackResult DeleteModuleDataCallback(const TCHAR *key, const void *value, void *data)
163 {
164 return ((ModuleData *)value)->deleteFromDatabase(((ModuleDataDatabaseCallbackParams *)data)->hdb, ((ModuleDataDatabaseCallbackParams *)data)->id) ? _CONTINUE : _STOP;
165 }
166
167 /**
168 * Delete object from database
169 */
170 bool NetObj::deleteFromDatabase(DB_HANDLE hdb)
171 {
172 // Delete ACL
173 bool success = executeQueryOnObject(hdb, _T("DELETE FROM acl WHERE object_id=?"));
174 if (success)
175 success = executeQueryOnObject(hdb, _T("DELETE FROM object_properties WHERE object_id=?"));
176 if (success)
177 success = executeQueryOnObject(hdb, _T("DELETE FROM object_custom_attributes WHERE object_id=?"));
178
179 // Delete events
180 if (success && ConfigReadInt(_T("DeleteEventsOfDeletedObject"), 1))
181 {
182 success = executeQueryOnObject(hdb, _T("DELETE FROM event_log WHERE event_source=?"));
183 }
184
185 // Delete alarms
186 if (success && ConfigReadInt(_T("DeleteAlarmsOfDeletedObject"), 1))
187 {
188 success = DeleteObjectAlarms(m_id, hdb);
189 }
190
191 // Delete module data
192 if (success && (m_moduleData != NULL))
193 {
194 ModuleDataDatabaseCallbackParams data;
195 data.id = m_id;
196 data.hdb = hdb;
197 success = (m_moduleData->forEach(DeleteModuleDataCallback, &data) == _CONTINUE);
198 }
199
200 return success;
201 }
202
203 /**
204 * Load common object properties from database
205 */
206 bool NetObj::loadCommonProperties(DB_HANDLE hdb)
207 {
208 bool success = false;
209
210 // Load access options
211 DB_STATEMENT hStmt = DBPrepare(hdb,
212 _T("SELECT name,status,is_deleted,")
213 _T("inherit_access_rights,last_modified,status_calc_alg,")
214 _T("status_prop_alg,status_fixed_val,status_shift,")
215 _T("status_translation,status_single_threshold,")
216 _T("status_thresholds,comments,is_system,")
217 _T("location_type,latitude,longitude,location_accuracy,")
218 _T("location_timestamp,guid,image,submap_id,country,city,")
219 _T("street_address,postcode,maint_mode,maint_event_id FROM object_properties ")
220 _T("WHERE object_id=?"));
221 if (hStmt != NULL)
222 {
223 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
224 DB_RESULT hResult = DBSelectPrepared(hStmt);
225 if (hResult != NULL)
226 {
227 if (DBGetNumRows(hResult) > 0)
228 {
229 DBGetField(hResult, 0, 0, m_name, MAX_OBJECT_NAME);
230 m_status = DBGetFieldLong(hResult, 0, 1);
231 m_isDeleted = DBGetFieldLong(hResult, 0, 2) ? true : false;
232 m_inheritAccessRights = DBGetFieldLong(hResult, 0, 3) ? true : false;
233 m_dwTimeStamp = DBGetFieldULong(hResult, 0, 4);
234 m_statusCalcAlg = DBGetFieldLong(hResult, 0, 5);
235 m_statusPropAlg = DBGetFieldLong(hResult, 0, 6);
236 m_fixedStatus = DBGetFieldLong(hResult, 0, 7);
237 m_statusShift = DBGetFieldLong(hResult, 0, 8);
238 DBGetFieldByteArray(hResult, 0, 9, m_statusTranslation, 4, STATUS_WARNING);
239 m_statusSingleThreshold = DBGetFieldLong(hResult, 0, 10);
240 DBGetFieldByteArray(hResult, 0, 11, m_statusThresholds, 4, 50);
241 safe_free(m_comments);
242 m_comments = DBGetField(hResult, 0, 12, NULL, 0);
243 m_isSystem = DBGetFieldLong(hResult, 0, 13) ? true : false;
244
245 int locType = DBGetFieldLong(hResult, 0, 14);
246 if (locType != GL_UNSET)
247 {
248 TCHAR lat[32], lon[32];
249
250 DBGetField(hResult, 0, 15, lat, 32);
251 DBGetField(hResult, 0, 16, lon, 32);
252 m_geoLocation = GeoLocation(locType, lat, lon, DBGetFieldLong(hResult, 0, 17), DBGetFieldULong(hResult, 0, 18));
253 }
254 else
255 {
256 m_geoLocation = GeoLocation();
257 }
258
259 m_guid = DBGetFieldGUID(hResult, 0, 19);
260 m_image = DBGetFieldGUID(hResult, 0, 20);
261 m_submapId = DBGetFieldULong(hResult, 0, 21);
262
263 TCHAR country[64], city[64], streetAddress[256], postcode[32];
264 DBGetField(hResult, 0, 22, country, 64);
265 DBGetField(hResult, 0, 23, city, 64);
266 DBGetField(hResult, 0, 24, streetAddress, 256);
267 DBGetField(hResult, 0, 25, postcode, 32);
268 delete m_postalAddress;
269 m_postalAddress = new PostalAddress(country, city, streetAddress, postcode);
270
271 m_maintenanceMode = DBGetFieldLong(hResult, 0, 26) ? true : false;
272 m_maintenanceEventId = DBGetFieldUInt64(hResult, 0, 27);
273
274 success = true;
275 }
276 DBFreeResult(hResult);
277 }
278 DBFreeStatement(hStmt);
279 }
280
281 // Load custom attributes
282 if (success)
283 {
284 hStmt = DBPrepare(hdb, _T("SELECT attr_name,attr_value FROM object_custom_attributes WHERE object_id=?"));
285 if (hStmt != NULL)
286 {
287 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
288 DB_RESULT hResult = DBSelectPrepared(hStmt);
289 if (hResult != NULL)
290 {
291 int i, count;
292 TCHAR *name, *value;
293
294 count = DBGetNumRows(hResult);
295 for(i = 0; i < count; i++)
296 {
297 name = DBGetField(hResult, i, 0, NULL, 0);
298 if (name != NULL)
299 {
300 value = DBGetField(hResult, i, 1, NULL, 0);
301 if (value != NULL)
302 {
303 m_customAttributes.setPreallocated(name, value);
304 }
305 }
306 }
307 DBFreeResult(hResult);
308 }
309 else
310 {
311 success = false;
312 }
313 DBFreeStatement(hStmt);
314 }
315 else
316 {
317 success = false;
318 }
319 }
320
321 // Load associated dashboards
322 if (success)
323 {
324 hStmt = DBPrepare(hdb, _T("SELECT dashboard_id FROM dashboard_associations WHERE object_id=?"));
325 if (hStmt != NULL)
326 {
327 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
328 DB_RESULT hResult = DBSelectPrepared(hStmt);
329 if (hResult != NULL)
330 {
331 int count = DBGetNumRows(hResult);
332 for(int i = 0; i < count; i++)
333 {
334 m_dashboards->add(DBGetFieldULong(hResult, i, 0));
335 }
336 DBFreeResult(hResult);
337 }
338 else
339 {
340 success = false;
341 }
342 DBFreeStatement(hStmt);
343 }
344 else
345 {
346 success = false;
347 }
348 }
349
350 if (success)
351 success = loadTrustedNodes(hdb);
352
353 if (!success)
354 DbgPrintf(4, _T("NetObj::loadCommonProperties() failed for object %s [%ld] class=%d"), m_name, (long)m_id, getObjectClass());
355
356 return success;
357 }
358
359 /**
360 * Callback for saving custom attribute in database
361 */
362 static EnumerationCallbackResult SaveAttributeCallback(const TCHAR *key, const void *value, void *data)
363 {
364 DB_STATEMENT hStmt = (DB_STATEMENT)data;
365 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, key, DB_BIND_STATIC);
366 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, (const TCHAR *)value, DB_BIND_STATIC);
367 return DBExecute(hStmt) ? _CONTINUE : _STOP;
368 }
369
370 /**
371 * Callback for saving module data in database
372 */
373 static EnumerationCallbackResult SaveModuleDataCallback(const TCHAR *key, const void *value, void *data)
374 {
375 return ((ModuleData *)value)->saveToDatabase(((ModuleDataDatabaseCallbackParams *)data)->hdb, ((ModuleDataDatabaseCallbackParams *)data)->id) ? _CONTINUE : _STOP;
376 }
377
378 /**
379 * Save common object properties to database
380 */
381 bool NetObj::saveCommonProperties(DB_HANDLE hdb)
382 {
383 DB_STATEMENT hStmt;
384 if (IsDatabaseRecordExist(hdb, _T("object_properties"), _T("object_id"), m_id))
385 {
386 hStmt = DBPrepare(hdb,
387 _T("UPDATE object_properties SET name=?,status=?,")
388 _T("is_deleted=?,inherit_access_rights=?,")
389 _T("last_modified=?,status_calc_alg=?,status_prop_alg=?,")
390 _T("status_fixed_val=?,status_shift=?,status_translation=?,")
391 _T("status_single_threshold=?,status_thresholds=?,")
392 _T("comments=?,is_system=?,location_type=?,latitude=?,")
393 _T("longitude=?,location_accuracy=?,location_timestamp=?,")
394 _T("guid=?,image=?,submap_id=?,country=?,city=?,")
395 _T("street_address=?,postcode=?,maint_mode=?,maint_event_id=? WHERE object_id=?"));
396 }
397 else
398 {
399 hStmt = DBPrepare(hdb,
400 _T("INSERT INTO object_properties (name,status,is_deleted,")
401 _T("inherit_access_rights,last_modified,status_calc_alg,")
402 _T("status_prop_alg,status_fixed_val,status_shift,status_translation,")
403 _T("status_single_threshold,status_thresholds,comments,is_system,")
404 _T("location_type,latitude,longitude,location_accuracy,location_timestamp,")
405 _T("guid,image,submap_id,country,city,street_address,postcode,maint_mode,")
406 _T("maint_event_id,object_id) ")
407 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
408 }
409 if (hStmt == NULL)
410 return false;
411
412 TCHAR szTranslation[16], szThresholds[16], lat[32], lon[32];
413 for(int i = 0, j = 0; i < 4; i++, j += 2)
414 {
415 _sntprintf(&szTranslation[j], 16 - j, _T("%02X"), (BYTE)m_statusTranslation[i]);
416 _sntprintf(&szThresholds[j], 16 - j, _T("%02X"), (BYTE)m_statusThresholds[i]);
417 }
418 _sntprintf(lat, 32, _T("%f"), m_geoLocation.getLatitude());
419 _sntprintf(lon, 32, _T("%f"), m_geoLocation.getLongitude());
420
421 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_name, DB_BIND_STATIC);
422 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (LONG)m_status);
423 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)(m_isDeleted ? 1 : 0));
424 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (LONG)(m_inheritAccessRights ? 1 : 0));
425 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_dwTimeStamp);
426 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (LONG)m_statusCalcAlg);
427 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (LONG)m_statusPropAlg);
428 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_fixedStatus);
429 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_statusShift);
430 DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, szTranslation, DB_BIND_STATIC);
431 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, (LONG)m_statusSingleThreshold);
432 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, szThresholds, DB_BIND_STATIC);
433 DBBind(hStmt, 13, DB_SQLTYPE_VARCHAR, m_comments, DB_BIND_STATIC);
434 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (LONG)(m_isSystem ? 1 : 0));
435 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getType());
436 DBBind(hStmt, 16, DB_SQLTYPE_VARCHAR, lat, DB_BIND_STATIC);
437 DBBind(hStmt, 17, DB_SQLTYPE_VARCHAR, lon, DB_BIND_STATIC);
438 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getAccuracy());
439 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
440 DBBind(hStmt, 20, DB_SQLTYPE_VARCHAR, m_guid);
441 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, m_image);
442 DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, m_submapId);
443 DBBind(hStmt, 23, DB_SQLTYPE_VARCHAR, m_postalAddress->getCountry(), DB_BIND_STATIC);
444 DBBind(hStmt, 24, DB_SQLTYPE_VARCHAR, m_postalAddress->getCity(), DB_BIND_STATIC);
445 DBBind(hStmt, 25, DB_SQLTYPE_VARCHAR, m_postalAddress->getStreetAddress(), DB_BIND_STATIC);
446 DBBind(hStmt, 26, DB_SQLTYPE_VARCHAR, m_postalAddress->getPostCode(), DB_BIND_STATIC);
447 DBBind(hStmt, 27, DB_SQLTYPE_VARCHAR, m_maintenanceMode ? _T("1") : _T("0"), DB_BIND_STATIC);
448 DBBind(hStmt, 28, DB_SQLTYPE_BIGINT, m_maintenanceEventId);
449 DBBind(hStmt, 29, DB_SQLTYPE_INTEGER, m_id);
450
451 bool success = DBExecute(hStmt);
452 DBFreeStatement(hStmt);
453
454 // Save custom attributes
455 if (success)
456 {
457 TCHAR szQuery[512];
458 _sntprintf(szQuery, 512, _T("DELETE FROM object_custom_attributes WHERE object_id=%d"), m_id);
459 success = DBQuery(hdb, szQuery);
460 if (success)
461 {
462 hStmt = DBPrepare(hdb, _T("INSERT INTO object_custom_attributes (object_id,attr_name,attr_value) VALUES (?,?,?)"));
463 if (hStmt != NULL)
464 {
465 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
466 success = (m_customAttributes.forEach(SaveAttributeCallback, hStmt) == _CONTINUE);
467 DBFreeStatement(hStmt);
468 }
469 else
470 {
471 success = false;
472 }
473 }
474 }
475
476 // Save dashboard associations
477 if (success)
478 {
479 TCHAR szQuery[512];
480 _sntprintf(szQuery, 512, _T("DELETE FROM dashboard_associations WHERE object_id=%d"), m_id);
481 success = DBQuery(hdb, szQuery);
482 if (success && (m_dashboards->size() > 0))
483 {
484 hStmt = DBPrepare(hdb, _T("INSERT INTO dashboard_associations (object_id,dashboard_id) VALUES (?,?)"));
485 if (hStmt != NULL)
486 {
487 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
488 for(int i = 0; (i < m_dashboards->size()) && success; i++)
489 {
490 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dashboards->get(i));
491 success = DBExecute(hStmt);
492 }
493 DBFreeStatement(hStmt);
494 }
495 else
496 {
497 success = false;
498 }
499 }
500 }
501
502 // Save module data
503 if (success && (m_moduleData != NULL))
504 {
505 ModuleDataDatabaseCallbackParams data;
506 data.id = m_id;
507 data.hdb = hdb;
508 success = (m_moduleData->forEach(SaveModuleDataCallback, &data) == _CONTINUE);
509 }
510
511 if (success)
512 success = saveTrustedNodes(hdb);
513
514 return success;
515 }
516
517 /**
518 * Add reference to the new child object
519 */
520 void NetObj::addChild(NetObj *object)
521 {
522 lockChildList(true);
523 if (m_childList->contains(object))
524 {
525 unlockChildList();
526 return; // Already in the child list
527 }
528 m_childList->add(object);
529 unlockChildList();
530 incRefCount();
531 setModified();
532 DbgPrintf(7, _T("NetObj::addChild: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
533 }
534
535 /**
536 * Add reference to parent object
537 */
538 void NetObj::addParent(NetObj *object)
539 {
540 lockParentList(true);
541 if (m_parentList->contains(object))
542 {
543 unlockParentList();
544 return; // Already in the parents list
545 }
546 m_parentList->add(object);
547 unlockParentList();
548 incRefCount();
549 setModified();
550 DbgPrintf(7, _T("NetObj::addParent: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
551 }
552
553 /**
554 * Delete reference to child object
555 */
556 void NetObj::deleteChild(NetObj *object)
557 {
558 int i;
559
560 lockChildList(true);
561 for(i = 0; i < m_childList->size(); i++)
562 if (m_childList->get(i) == object)
563 break;
564
565 if (i == m_childList->size()) // No such object
566 {
567 unlockChildList();
568 return;
569 }
570
571 DbgPrintf(7, _T("NetObj::deleteChild: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
572 m_childList->remove(i);
573 unlockChildList();
574 decRefCount();
575 setModified();
576 }
577
578 /**
579 * Delete reference to parent object
580 */
581 void NetObj::deleteParent(NetObj *object)
582 {
583 int i;
584
585 lockParentList(true);
586 for(i = 0; i < m_parentList->size(); i++)
587 if (m_parentList->get(i) == object)
588 break;
589 if (i == m_parentList->size()) // No such object
590 {
591 unlockParentList();
592 return;
593 }
594
595 DbgPrintf(7, _T("NetObj::deleteParent: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
596
597 m_parentList->remove(i);
598 unlockParentList();
599 decRefCount();
600 setModified();
601 }
602
603 /**
604 * Walker callback to call OnObjectDelete for each active object
605 */
606 void NetObj::onObjectDeleteCallback(NetObj *object, void *data)
607 {
608 UINT32 currId = ((NetObj *)data)->getId();
609 if ((object->getId() != currId) && !object->isDeleted())
610 object->onObjectDelete(currId);
611 }
612
613 /**
614 * Prepare object for deletion - remove all references, etc.
615 *
616 * @param initiator pointer to parent object which causes recursive deletion or NULL
617 */
618 void NetObj::deleteObject(NetObj *initiator)
619 {
620 DbgPrintf(4, _T("Deleting object %d [%s]"), m_id, m_name);
621
622 // Prevent object change propagation until it's marked as deleted
623 // (to prevent the object's incorrect appearance in GUI
624 lockProperties();
625 m_isHidden = true;
626 unlockProperties();
627
628 // Notify modules about object deletion
629 CALL_ALL_MODULES(pfPreObjectDelete, (this));
630
631 prepareForDeletion();
632
633 DbgPrintf(5, _T("NetObj::deleteObject(): deleting object %d from indexes"), m_id);
634 NetObjDeleteFromIndexes(this);
635
636 // Delete references to this object from child objects
637 DbgPrintf(5, _T("NetObj::deleteObject(): clearing child list for object %d"), m_id);
638 ObjectArray<NetObj> *deleteList = NULL;
639 lockChildList(true);
640 for(int i = 0; i < m_childList->size(); i++)
641 {
642 NetObj *o = m_childList->get(i);
643 if (o->getParentCount() == 1)
644 {
645 // last parent, delete object
646 if (deleteList == NULL)
647 deleteList = new ObjectArray<NetObj>(16, 16, false);
648 deleteList->add(o);
649 }
650 else
651 {
652 o->deleteParent(this);
653 }
654 decRefCount();
655 }
656 m_childList->clear();
657 unlockChildList();
658
659 // Delete orphaned child objects
660 if (deleteList != NULL)
661 {
662 for(int i = 0; i < deleteList->size(); i++)
663 {
664 NetObj *obj = deleteList->get(i);
665 DbgPrintf(5, _T("NetObj::deleteObject(): calling deleteObject() on %s [%d]"), obj->getName(), obj->getId());
666 obj->deleteObject(this);
667 }
668 delete deleteList;
669 }
670
671 // Remove references to this object from parent objects
672 DbgPrintf(5, _T("NetObj::Delete(): clearing parent list for object %d"), m_id);
673 lockParentList(true);
674 for(int i = 0; i < m_parentList->size(); i++)
675 {
676 // If parent is deletion initiator then this object already
677 // removed from parent's list
678 NetObj *obj = m_parentList->get(i);
679 if (obj != initiator)
680 {
681 obj->deleteChild(this);
682 obj->calculateCompoundStatus();
683 }
684 decRefCount();
685 }
686 m_parentList->clear();
687 unlockParentList();
688
689 lockProperties();
690 m_isHidden = false;
691 m_isDeleted = true;
692 setModified();
693 unlockProperties();
694
695 // Notify all other objects about object deletion
696 DbgPrintf(5, _T("NetObj::deleteObject(): calling onObjectDelete(%d)"), m_id);
697 g_idxObjectById.forEach(onObjectDeleteCallback, this);
698
699 DbgPrintf(4, _T("Object %d successfully deleted"), m_id);
700 }
701
702 /**
703 * Default handler for object deletion notification
704 */
705 void NetObj::onObjectDelete(UINT32 dwObjectId)
706 {
707 }
708
709 /**
710 * Get childs IDs in printable form
711 */
712 const TCHAR *NetObj::dbgGetChildList(TCHAR *szBuffer)
713 {
714 TCHAR *pBuf = szBuffer;
715 *pBuf = 0;
716 lockChildList(false);
717 for(int i = 0; i < m_childList->size(); i++)
718 {
719 _sntprintf(pBuf, 10, _T("%d "), m_childList->get(i)->getId());
720 while(*pBuf)
721 pBuf++;
722 }
723 unlockChildList();
724 if (pBuf != szBuffer)
725 *(pBuf - 1) = 0;
726 return szBuffer;
727 }
728
729 /**
730 * Get parents IDs in printable form
731 */
732 const TCHAR *NetObj::dbgGetParentList(TCHAR *szBuffer)
733 {
734 TCHAR *pBuf = szBuffer;
735 *pBuf = 0;
736 lockParentList(false);
737 for(int i = 0; i < m_parentList->size(); i++)
738 {
739 _sntprintf(pBuf, 10, _T("%d "), m_parentList->get(i)->getId());
740 while(*pBuf)
741 pBuf++;
742 }
743 unlockParentList();
744 if (pBuf != szBuffer)
745 *(pBuf - 1) = 0;
746 return szBuffer;
747 }
748
749 /**
750 * Calculate status for compound object based on childs' status
751 */
752 void NetObj::calculateCompoundStatus(BOOL bForcedRecalc)
753 {
754 if (m_status == STATUS_UNMANAGED)
755 return;
756
757 int mostCriticalAlarm = GetMostCriticalStatusForObject(m_id);
758 int mostCriticalDCI =
759 (getObjectClass() == OBJECT_NODE || getObjectClass() == OBJECT_MOBILEDEVICE || getObjectClass() == OBJECT_CLUSTER || getObjectClass() == OBJECT_ACCESSPOINT) ?
760 ((DataCollectionTarget *)this)->getMostCriticalDCIStatus() : STATUS_UNKNOWN;
761
762 int oldStatus = m_status;
763 int mostCriticalStatus, i, count, iStatusAlg;
764 int nSingleThreshold, *pnThresholds;
765 int nRating[5], iChildStatus, nThresholds[4];
766
767 lockProperties();
768 if (m_statusCalcAlg == SA_CALCULATE_DEFAULT)
769 {
770 iStatusAlg = GetDefaultStatusCalculation(&nSingleThreshold, &pnThresholds);
771 }
772 else
773 {
774 iStatusAlg = m_statusCalcAlg;
775 nSingleThreshold = m_statusSingleThreshold;
776 pnThresholds = m_statusThresholds;
777 }
778 if (iStatusAlg == SA_CALCULATE_SINGLE_THRESHOLD)
779 {
780 for(i = 0; i < 4; i++)
781 nThresholds[i] = nSingleThreshold;
782 pnThresholds = nThresholds;
783 }
784
785 switch(iStatusAlg)
786 {
787 case SA_CALCULATE_MOST_CRITICAL:
788 lockChildList(false);
789 for(i = 0, count = 0, mostCriticalStatus = -1; i < m_childList->size(); i++)
790 {
791 iChildStatus = m_childList->get(i)->getPropagatedStatus();
792 if ((iChildStatus < STATUS_UNKNOWN) &&
793 (iChildStatus > mostCriticalStatus))
794 {
795 mostCriticalStatus = iChildStatus;
796 count++;
797 }
798 }
799 m_status = (count > 0) ? mostCriticalStatus : STATUS_UNKNOWN;
800 unlockChildList();
801 break;
802 case SA_CALCULATE_SINGLE_THRESHOLD:
803 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
804 // Step 1: calculate severity raitings
805 memset(nRating, 0, sizeof(int) * 5);
806 lockChildList(false);
807 for(i = 0, count = 0; i < m_childList->size(); i++)
808 {
809 iChildStatus = m_childList->get(i)->getPropagatedStatus();
810 if (iChildStatus < STATUS_UNKNOWN)
811 {
812 while(iChildStatus >= 0)
813 nRating[iChildStatus--]++;
814 count++;
815 }
816 }
817 unlockChildList();
818
819 // Step 2: check what severity rating is above threshold
820 if (count > 0)
821 {
822 for(i = 4; i > 0; i--)
823 if (nRating[i] * 100 / count >= pnThresholds[i - 1])
824 break;
825 m_status = i;
826 }
827 else
828 {
829 m_status = STATUS_UNKNOWN;
830 }
831 break;
832 default:
833 m_status = STATUS_UNKNOWN;
834 break;
835 }
836
837 // If alarms exist for object, apply alarm severity to object's status
838 if (mostCriticalAlarm != STATUS_UNKNOWN)
839 {
840 if (m_status == STATUS_UNKNOWN)
841 {
842 m_status = mostCriticalAlarm;
843 }
844 else
845 {
846 m_status = max(m_status, mostCriticalAlarm);
847 }
848 }
849
850 // If DCI status is calculated for object apply DCI object's statud
851 if (mostCriticalDCI != STATUS_UNKNOWN)
852 {
853 if (m_status == STATUS_UNKNOWN)
854 {
855 m_status = mostCriticalDCI;
856 }
857 else
858 {
859 m_status = max(m_status, mostCriticalDCI);
860 }
861 }
862
863 // Query loaded modules for object status
864 ENUMERATE_MODULES(pfCalculateObjectStatus)
865 {
866 int moduleStatus = g_pModuleList[__i].pfCalculateObjectStatus(this);
867 if (moduleStatus != STATUS_UNKNOWN)
868 {
869 if (m_status == STATUS_UNKNOWN)
870 {
871 m_status = moduleStatus;
872 }
873 else
874 {
875 m_status = max(m_status, moduleStatus);
876 }
877 }
878 }
879
880 unlockProperties();
881
882 // Cause parent object(s) to recalculate it's status
883 if ((oldStatus != m_status) || bForcedRecalc)
884 {
885 lockParentList(false);
886 for(i = 0; i < m_parentList->size(); i++)
887 m_parentList->get(i)->calculateCompoundStatus();
888 unlockParentList();
889 lockProperties();
890 setModified();
891 unlockProperties();
892 }
893 }
894
895 /**
896 * Load ACL from database
897 */
898 bool NetObj::loadACLFromDB(DB_HANDLE hdb)
899 {
900 bool success = false;
901
902 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT user_id,access_rights FROM acl WHERE object_id=?"));
903 if (hStmt != NULL)
904 {
905 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
906 DB_RESULT hResult = DBSelectPrepared(hStmt);
907 if (hResult != NULL)
908 {
909 int count = DBGetNumRows(hResult);
910 for(int i = 0; i < count; i++)
911 m_accessList->addElement(DBGetFieldULong(hResult, i, 0), DBGetFieldULong(hResult, i, 1));
912 DBFreeResult(hResult);
913 success = true;
914 }
915 DBFreeStatement(hStmt);
916 }
917 return success;
918 }
919
920 /**
921 * ACL enumeration parameters structure
922 */
923 struct SAVE_PARAM
924 {
925 DB_HANDLE hdb;
926 UINT32 dwObjectId;
927 };
928
929 /**
930 * Handler for ACL elements enumeration
931 */
932 static void EnumerationHandler(UINT32 dwUserId, UINT32 dwAccessRights, void *pArg)
933 {
934 TCHAR szQuery[256];
935
936 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO acl (object_id,user_id,access_rights) VALUES (%d,%d,%d)"),
937 ((SAVE_PARAM *)pArg)->dwObjectId, dwUserId, dwAccessRights);
938 DBQuery(((SAVE_PARAM *)pArg)->hdb, szQuery);
939 }
940
941 /**
942 * Save ACL to database
943 */
944 bool NetObj::saveACLToDB(DB_HANDLE hdb)
945 {
946 TCHAR szQuery[256];
947 bool success = false;
948 SAVE_PARAM sp;
949
950 // Save access list
951 lockACL();
952 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM acl WHERE object_id=%d"), m_id);
953 if (DBQuery(hdb, szQuery))
954 {
955 sp.dwObjectId = m_id;
956 sp.hdb = hdb;
957 m_accessList->enumerateElements(EnumerationHandler, &sp);
958 success = true;
959 }
960 unlockACL();
961 return success;
962 }
963
964 /**
965 * Data for SendModuleDataCallback
966 */
967 struct SendModuleDataCallbackData
968 {
969 NXCPMessage *msg;
970 UINT32 id;
971 };
972
973 /**
974 * Callback for sending module data in NXCP message
975 */
976 static EnumerationCallbackResult SendModuleDataCallback(const TCHAR *key, const void *value, void *data)
977 {
978 ((SendModuleDataCallbackData *)data)->msg->setField(((SendModuleDataCallbackData *)data)->id, key);
979 ((ModuleData *)value)->fillMessage(((SendModuleDataCallbackData *)data)->msg, ((SendModuleDataCallbackData *)data)->id + 1);
980 ((SendModuleDataCallbackData *)data)->id += 0x100000;
981 return _CONTINUE;
982 }
983
984 /**
985 * Fill NXCP message with object's data
986 * Object's properties are locked when this method is called. Method should not do any other locks.
987 * Data required other locks should be filled in fillMessageInternalStage2().
988 */
989 void NetObj::fillMessageInternal(NXCPMessage *pMsg)
990 {
991 pMsg->setField(VID_OBJECT_CLASS, (WORD)getObjectClass());
992 pMsg->setField(VID_OBJECT_ID, m_id);
993 pMsg->setField(VID_GUID, m_guid);
994 pMsg->setField(VID_OBJECT_NAME, m_name);
995 pMsg->setField(VID_OBJECT_STATUS, (WORD)m_status);
996 pMsg->setField(VID_IS_DELETED, (WORD)(m_isDeleted ? 1 : 0));
997 pMsg->setField(VID_IS_SYSTEM, (INT16)(m_isSystem ? 1 : 0));
998 pMsg->setField(VID_MAINTENANCE_MODE, (INT16)(m_maintenanceEventId ? 1 : 0));
999
1000 pMsg->setField(VID_INHERIT_RIGHTS, m_inheritAccessRights);
1001 pMsg->setField(VID_STATUS_CALCULATION_ALG, (WORD)m_statusCalcAlg);
1002 pMsg->setField(VID_STATUS_PROPAGATION_ALG, (WORD)m_statusPropAlg);
1003 pMsg->setField(VID_FIXED_STATUS, (WORD)m_fixedStatus);
1004 pMsg->setField(VID_STATUS_SHIFT, (WORD)m_statusShift);
1005 pMsg->setField(VID_STATUS_TRANSLATION_1, (WORD)m_statusTranslation[0]);
1006 pMsg->setField(VID_STATUS_TRANSLATION_2, (WORD)m_statusTranslation[1]);
1007 pMsg->setField(VID_STATUS_TRANSLATION_3, (WORD)m_statusTranslation[2]);
1008 pMsg->setField(VID_STATUS_TRANSLATION_4, (WORD)m_statusTranslation[3]);
1009 pMsg->setField(VID_STATUS_SINGLE_THRESHOLD, (WORD)m_statusSingleThreshold);
1010 pMsg->setField(VID_STATUS_THRESHOLD_1, (WORD)m_statusThresholds[0]);
1011 pMsg->setField(VID_STATUS_THRESHOLD_2, (WORD)m_statusThresholds[1]);
1012 pMsg->setField(VID_STATUS_THRESHOLD_3, (WORD)m_statusThresholds[2]);
1013 pMsg->setField(VID_STATUS_THRESHOLD_4, (WORD)m_statusThresholds[3]);
1014 pMsg->setField(VID_COMMENTS, CHECK_NULL_EX(m_comments));
1015 pMsg->setField(VID_IMAGE, m_image);
1016 pMsg->setField(VID_SUBMAP_ID, m_submapId);
1017 pMsg->setField(VID_NUM_TRUSTED_NODES, m_dwNumTrustedNodes);
1018 if (m_dwNumTrustedNodes > 0)
1019 pMsg->setFieldFromInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
1020 pMsg->setFieldFromInt32Array(VID_DASHBOARDS, m_dashboards);
1021
1022 m_customAttributes.fillMessage(pMsg, VID_NUM_CUSTOM_ATTRIBUTES, VID_CUSTOM_ATTRIBUTES_BASE);
1023
1024 m_geoLocation.fillMessage(*pMsg);
1025
1026 pMsg->setField(VID_COUNTRY, m_postalAddress->getCountry());
1027 pMsg->setField(VID_CITY, m_postalAddress->getCity());
1028 pMsg->setField(VID_STREET_ADDRESS, m_postalAddress->getStreetAddress());
1029 pMsg->setField(VID_POSTCODE, m_postalAddress->getPostCode());
1030
1031 if (m_moduleData != NULL)
1032 {
1033 pMsg->setField(VID_MODULE_DATA_COUNT, (UINT16)m_moduleData->size());
1034 SendModuleDataCallbackData data;
1035 data.msg = pMsg;
1036 data.id = VID_MODULE_DATA_BASE;
1037 m_moduleData->forEach(SendModuleDataCallback, &data);
1038 }
1039 else
1040 {
1041 pMsg->setField(VID_MODULE_DATA_COUNT, (UINT16)0);
1042 }
1043 }
1044
1045 /**
1046 * Fill NXCP message with object's data - stage 2
1047 * Object's properties are not locked when this method is called. Should be
1048 * used only to fill data where properties lock is not enough (like data
1049 * collection configuration).
1050 */
1051 void NetObj::fillMessageInternalStage2(NXCPMessage *pMsg)
1052 {
1053 }
1054
1055 /**
1056 * Fill NXCP message with object's data
1057 */
1058 void NetObj::fillMessage(NXCPMessage *msg)
1059 {
1060 lockProperties();
1061 fillMessageInternal(msg);
1062 unlockProperties();
1063 fillMessageInternalStage2(msg);
1064
1065 lockACL();
1066 m_accessList->fillMessage(msg);
1067 unlockACL();
1068
1069 UINT32 dwId;
1070 int i;
1071
1072 lockParentList(false);
1073 msg->setField(VID_PARENT_CNT, m_parentList->size());
1074 for(i = 0, dwId = VID_PARENT_ID_BASE; i < m_parentList->size(); i++, dwId++)
1075 msg->setField(dwId, m_parentList->get(i)->getId());
1076 unlockParentList();
1077
1078 lockChildList(false);
1079 msg->setField(VID_CHILD_CNT, m_childList->size());
1080 for(i = 0, dwId = VID_CHILD_ID_BASE; i < m_childList->size(); i++, dwId++)
1081 msg->setField(dwId, m_childList->get(i)->getId());
1082 unlockChildList();
1083 }
1084
1085 /**
1086 * Handler for EnumerateSessions()
1087 */
1088 static void BroadcastObjectChange(ClientSession *pSession, void *pArg)
1089 {
1090 if (pSession->isAuthenticated())
1091 pSession->onObjectChange((NetObj *)pArg);
1092 }
1093
1094 /**
1095 * Mark object as modified and put on client's notification queue
1096 * We assume that object is locked at the time of function call
1097 */
1098 void NetObj::setModified(bool notify)
1099 {
1100 if (g_bModificationsLocked)
1101 return;
1102
1103 m_isModified = true;
1104 m_dwTimeStamp = (UINT32)time(NULL);
1105
1106 // Send event to all connected clients
1107 if (notify && !m_isHidden && !m_isSystem)
1108 EnumerateClientSessions(BroadcastObjectChange, this);
1109 }
1110
1111 /**
1112 * Modify object from NXCP message - common wrapper
1113 */
1114 UINT32 NetObj::modifyFromMessage(NXCPMessage *msg)
1115 {
1116 lockProperties();
1117 UINT32 rcc = modifyFromMessageInternal(msg);
1118 setModified();
1119 unlockProperties();
1120 return rcc;
1121 }
1122
1123 /**
1124 * Modify object from NXCP message
1125 */
1126 UINT32 NetObj::modifyFromMessageInternal(NXCPMessage *pRequest)
1127 {
1128 // Change object's name
1129 if (pRequest->isFieldExist(VID_OBJECT_NAME))
1130 pRequest->getFieldAsString(VID_OBJECT_NAME, m_name, MAX_OBJECT_NAME);
1131
1132 // Change object's status calculation/propagation algorithms
1133 if (pRequest->isFieldExist(VID_STATUS_CALCULATION_ALG))
1134 {
1135 m_statusCalcAlg = pRequest->getFieldAsInt16(VID_STATUS_CALCULATION_ALG);
1136 m_statusPropAlg = pRequest->getFieldAsInt16(VID_STATUS_PROPAGATION_ALG);
1137 m_fixedStatus = pRequest->getFieldAsInt16(VID_FIXED_STATUS);
1138 m_statusShift = pRequest->getFieldAsInt16(VID_STATUS_SHIFT);
1139 m_statusTranslation[0] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_1);
1140 m_statusTranslation[1] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_2);
1141 m_statusTranslation[2] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_3);
1142 m_statusTranslation[3] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_4);
1143 m_statusSingleThreshold = pRequest->getFieldAsInt16(VID_STATUS_SINGLE_THRESHOLD);
1144 m_statusThresholds[0] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_1);
1145 m_statusThresholds[1] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_2);
1146 m_statusThresholds[2] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_3);
1147 m_statusThresholds[3] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_4);
1148 }
1149
1150 // Change image
1151 if (pRequest->isFieldExist(VID_IMAGE))
1152 m_image = pRequest->getFieldAsGUID(VID_IMAGE);
1153
1154 // Change object's ACL
1155 if (pRequest->isFieldExist(VID_ACL_SIZE))
1156 {
1157 lockACL();
1158 m_inheritAccessRights = pRequest->getFieldAsBoolean(VID_INHERIT_RIGHTS);
1159 m_accessList->deleteAll();
1160 int count = pRequest->getFieldAsUInt32(VID_ACL_SIZE);
1161 for(int i = 0; i < count; i++)
1162 m_accessList->addElement(pRequest->getFieldAsUInt32(VID_ACL_USER_BASE + i),
1163 pRequest->getFieldAsUInt32(VID_ACL_RIGHTS_BASE + i));
1164 unlockACL();
1165 }
1166
1167 // Change trusted nodes list
1168 if (pRequest->isFieldExist(VID_NUM_TRUSTED_NODES))
1169 {
1170 m_dwNumTrustedNodes = pRequest->getFieldAsUInt32(VID_NUM_TRUSTED_NODES);
1171 m_pdwTrustedNodes = (UINT32 *)realloc(m_pdwTrustedNodes, sizeof(UINT32) * m_dwNumTrustedNodes);
1172 pRequest->getFieldAsInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
1173 }
1174
1175 // Change custom attributes
1176 if (pRequest->isFieldExist(VID_NUM_CUSTOM_ATTRIBUTES))
1177 {
1178 UINT32 i, dwId, dwNumElements;
1179 TCHAR *name, *value;
1180
1181 dwNumElements = pRequest->getFieldAsUInt32(VID_NUM_CUSTOM_ATTRIBUTES);
1182 m_customAttributes.clear();
1183 for(i = 0, dwId = VID_CUSTOM_ATTRIBUTES_BASE; i < dwNumElements; i++)
1184 {
1185 name = pRequest->getFieldAsString(dwId++);
1186 value = pRequest->getFieldAsString(dwId++);
1187 if ((name != NULL) && (value != NULL))
1188 m_customAttributes.setPreallocated(name, value);
1189 }
1190 }
1191
1192 // Change geolocation
1193 if (pRequest->isFieldExist(VID_GEOLOCATION_TYPE))
1194 {
1195 m_geoLocation = GeoLocation(*pRequest);
1196 addLocationToHistory();
1197 }
1198
1199 if (pRequest->isFieldExist(VID_SUBMAP_ID))
1200 {
1201 m_submapId = pRequest->getFieldAsUInt32(VID_SUBMAP_ID);
1202 }
1203
1204 if (pRequest->isFieldExist(VID_COUNTRY))
1205 {
1206 TCHAR buffer[64];
1207 pRequest->getFieldAsString(VID_COUNTRY, buffer, 64);
1208 m_postalAddress->setCountry(buffer);
1209 }
1210
1211 if (pRequest->isFieldExist(VID_CITY))
1212 {
1213 TCHAR buffer[64];
1214 pRequest->getFieldAsString(VID_CITY, buffer, 64);
1215 m_postalAddress->setCity(buffer);
1216 }
1217
1218 if (pRequest->isFieldExist(VID_STREET_ADDRESS))
1219 {
1220 TCHAR buffer[256];
1221 pRequest->getFieldAsString(VID_STREET_ADDRESS, buffer, 256);
1222 m_postalAddress->setStreetAddress(buffer);
1223 }
1224
1225 if (pRequest->isFieldExist(VID_POSTCODE))
1226 {
1227 TCHAR buffer[32];
1228 pRequest->getFieldAsString(VID_POSTCODE, buffer, 32);
1229 m_postalAddress->setPostCode(buffer);
1230 }
1231
1232 // Change dashboard list
1233 if (pRequest->isFieldExist(VID_DASHBOARDS))
1234 {
1235 pRequest->getFieldAsInt32Array(VID_DASHBOARDS, m_dashboards);
1236 }
1237
1238 return RCC_SUCCESS;
1239 }
1240
1241 /**
1242 * Post-modify hook
1243 */
1244 void NetObj::postModify()
1245 {
1246 calculateCompoundStatus(TRUE);
1247 }
1248
1249 /**
1250 * Get rights to object for specific user
1251 *
1252 * @param userId user object ID
1253 */
1254 UINT32 NetObj::getUserRights(UINT32 userId)
1255 {
1256 UINT32 dwRights;
1257
1258 // Admin always has all rights to any object
1259 if (userId == 0)
1260 return 0xFFFFFFFF;
1261
1262 // Non-admin users have no rights to system objects
1263 if (m_isSystem)
1264 return 0;
1265
1266 // Check if have direct right assignment
1267 lockACL();
1268 bool hasDirectRights = m_accessList->getUserRights(userId, &dwRights);
1269 unlockACL();
1270
1271 if (!hasDirectRights)
1272 {
1273 // We don't. If this object inherit rights from parents, get them
1274 if (m_inheritAccessRights)
1275 {
1276 dwRights = 0;
1277 lockParentList(false);
1278 for(int i = 0; i < m_parentList->size(); i++)
1279 dwRights |= m_parentList->get(i)->getUserRights(userId);
1280 unlockParentList();
1281 }
1282 }
1283
1284 return dwRights;
1285 }
1286
1287 /**
1288 * Check if given user has specific rights on this object
1289 *
1290 * @param userId user object ID
1291 * @param requiredRights bit mask of requested right
1292 * @return true if user has all rights specified in requested rights bit mask
1293 */
1294 BOOL NetObj::checkAccessRights(UINT32 userId, UINT32 requiredRights)
1295 {
1296 UINT32 effectiveRights = getUserRights(userId);
1297 return (effectiveRights & requiredRights) == requiredRights;
1298 }
1299
1300 /**
1301 * Drop all user privileges on current object
1302 */
1303 void NetObj::dropUserAccess(UINT32 dwUserId)
1304 {
1305 lockACL();
1306 bool modified = m_accessList->deleteElement(dwUserId);
1307 unlockACL();
1308 if (modified)
1309 {
1310 lockProperties();
1311 setModified();
1312 unlockProperties();
1313 }
1314 }
1315
1316 /**
1317 * Set object's management status
1318 */
1319 void NetObj::setMgmtStatus(BOOL bIsManaged)
1320 {
1321 int oldStatus;
1322
1323 lockProperties();
1324
1325 if ((bIsManaged && (m_status != STATUS_UNMANAGED)) ||
1326 ((!bIsManaged) && (m_status == STATUS_UNMANAGED)))
1327 {
1328 unlockProperties();
1329 return; // Status is already correct
1330 }
1331
1332 oldStatus = m_status;
1333 m_status = (bIsManaged ? STATUS_UNKNOWN : STATUS_UNMANAGED);
1334
1335 // Generate event if current object is a node
1336 if (getObjectClass() == OBJECT_NODE)
1337 PostEvent(bIsManaged ? EVENT_NODE_UNKNOWN : EVENT_NODE_UNMANAGED, m_id, "d", oldStatus);
1338
1339 setModified();
1340 unlockProperties();
1341
1342 // Change status for child objects also
1343 lockChildList(false);
1344 for(int i = 0; i < m_childList->size(); i++)
1345 m_childList->get(i)->setMgmtStatus(bIsManaged);
1346 unlockChildList();
1347
1348 // Cause parent object(s) to recalculate it's status
1349 lockParentList(false);
1350 for(int i = 0; i < m_parentList->size(); i++)
1351 m_parentList->get(i)->calculateCompoundStatus();
1352 unlockParentList();
1353 }
1354
1355 /**
1356 * Check if given object is an our child (possibly indirect, i.e child of child)
1357 *
1358 * @param id object ID to test
1359 */
1360 bool NetObj::isChild(UINT32 id)
1361 {
1362 bool bResult = false;
1363
1364 // Check for our own ID (object ID should never change, so we may not lock object's data)
1365 if (m_id == id)
1366 bResult = true;
1367
1368 // First, walk through our own child list
1369 if (!bResult)
1370 {
1371 lockChildList(false);
1372 for(int i = 0; i < m_childList->size(); i++)
1373 if (m_childList->get(i)->getId() == id)
1374 {
1375 bResult = true;
1376 break;
1377 }
1378 unlockChildList();
1379 }
1380
1381 // If given object is not in child list, check if it is indirect child
1382 if (!bResult)
1383 {
1384 lockChildList(false);
1385 for(int i = 0; i < m_childList->size(); i++)
1386 if (m_childList->get(i)->isChild(id))
1387 {
1388 bResult = true;
1389 break;
1390 }
1391 unlockChildList();
1392 }
1393
1394 return bResult;
1395 }
1396
1397 /**
1398 * Send message to client, who requests poll, if any
1399 * This method is used by Node and Interface class objects
1400 */
1401 void NetObj::sendPollerMsg(UINT32 dwRqId, const TCHAR *pszFormat, ...)
1402 {
1403 if (m_pollRequestor != NULL)
1404 {
1405 va_list args;
1406 TCHAR szBuffer[1024];
1407
1408 va_start(args, pszFormat);
1409 _vsntprintf(szBuffer, 1024, pszFormat, args);
1410 va_end(args);
1411 m_pollRequestor->sendPollerMsg(dwRqId, szBuffer);
1412 }
1413 }
1414
1415 /**
1416 * Add child node objects (direct and indirect childs) to list
1417 */
1418 void NetObj::addChildNodesToList(ObjectArray<Node> *nodeList, UINT32 dwUserId)
1419 {
1420 lockChildList(false);
1421
1422 // Walk through our own child list
1423 for(int i = 0; i < m_childList->size(); i++)
1424 {
1425 NetObj *object = m_childList->get(i);
1426 if (object->getObjectClass() == OBJECT_NODE)
1427 {
1428 // Check if this node already in the list
1429 int j;
1430 for(j = 0; j < nodeList->size(); j++)
1431 if (nodeList->get(j)->getId() == object->getId())
1432 break;
1433 if (j == nodeList->size())
1434 {
1435 object->incRefCount();
1436 nodeList->add((Node *)object);
1437 }
1438 }
1439 else
1440 {
1441 if (object->checkAccessRights(dwUserId, OBJECT_ACCESS_READ))
1442 object->addChildNodesToList(nodeList, dwUserId);
1443 }
1444 }
1445
1446 unlockChildList();
1447 }
1448
1449 /**
1450 * Add child data collection targets (direct and indirect childs) to list
1451 */
1452 void NetObj::addChildDCTargetsToList(ObjectArray<DataCollectionTarget> *dctList, UINT32 dwUserId)
1453 {
1454 lockChildList(false);
1455
1456 // Walk through our own child list
1457 for(int i = 0; i < m_childList->size(); i++)
1458 {
1459 NetObj *object = m_childList->get(i);
1460 if (!object->checkAccessRights(dwUserId, OBJECT_ACCESS_READ))
1461 continue;
1462
1463 if (object->isDataCollectionTarget())
1464 {
1465 // Check if this objects already in the list
1466 int j;
1467 for(j = 0; j < dctList->size(); j++)
1468 if (dctList->get(j)->getId() == object->getId())
1469 break;
1470 if (j == dctList->size())
1471 {
1472 object->incRefCount();
1473 dctList->add((DataCollectionTarget *)object);
1474 }
1475 }
1476 object->addChildDCTargetsToList(dctList, dwUserId);
1477 }
1478
1479 unlockChildList();
1480 }
1481
1482 /**
1483 * Hide object and all its childs
1484 */
1485 void NetObj::hide()
1486 {
1487 lockChildList(false);
1488 for(int i = 0; i < m_childList->size(); i++)
1489 m_childList->get(i)->hide();
1490 unlockChildList();
1491
1492 lockProperties();
1493 m_isHidden = true;
1494 unlockProperties();
1495 }
1496
1497 /**
1498 * Unhide object and all its childs
1499 */
1500 void NetObj::unhide()
1501 {
1502 lockProperties();
1503 m_isHidden = false;
1504 if (!m_isSystem)
1505 EnumerateClientSessions(BroadcastObjectChange, this);
1506 unlockProperties();
1507
1508 lockChildList(false);
1509 for(int i = 0; i < m_childList->size(); i++)
1510 m_childList->get(i)->unhide();
1511 unlockChildList();
1512 }
1513
1514 /**
1515 * Return status propagated to parent
1516 */
1517 int NetObj::getPropagatedStatus()
1518 {
1519 int iStatus;
1520
1521 if (m_statusPropAlg == SA_PROPAGATE_DEFAULT)
1522 {
1523 iStatus = DefaultPropagatedStatus(m_status);
1524 }
1525 else
1526 {
1527 switch(m_statusPropAlg)
1528 {
1529 case SA_PROPAGATE_UNCHANGED:
1530 iStatus = m_status;
1531 break;
1532 case SA_PROPAGATE_FIXED:
1533 iStatus = ((m_status > STATUS_NORMAL) && (m_status < STATUS_UNKNOWN)) ? m_fixedStatus : m_status;
1534 break;
1535 case SA_PROPAGATE_RELATIVE:
1536 if ((m_status > STATUS_NORMAL) && (m_status < STATUS_UNKNOWN))
1537 {
1538 iStatus = m_status + m_statusShift;
1539 if (iStatus < 0)
1540 iStatus = 0;
1541 if (iStatus > STATUS_CRITICAL)
1542 iStatus = STATUS_CRITICAL;
1543 }
1544 else
1545 {
1546 iStatus = m_status;
1547 }
1548 break;
1549 case SA_PROPAGATE_TRANSLATED:
1550 if ((m_status > STATUS_NORMAL) && (m_status < STATUS_UNKNOWN))
1551 {
1552 iStatus = m_statusTranslation[m_status - 1];
1553 }
1554 else
1555 {
1556 iStatus = m_status;
1557 }
1558 break;
1559 default:
1560 iStatus = STATUS_UNKNOWN;
1561 break;
1562 }
1563 }
1564 return iStatus;
1565 }
1566
1567 /**
1568 * Prepare object for deletion. Method should return only
1569 * when object deletion is safe
1570 */
1571 void NetObj::prepareForDeletion()
1572 {
1573 }
1574
1575 /**
1576 * Set object's comments.
1577 * NOTE: pszText should be dynamically allocated or NULL
1578 */
1579 void NetObj::setComments(TCHAR *text)
1580 {
1581 lockProperties();
1582 free(m_comments);
1583 m_comments = text;
1584 setModified();
1585 unlockProperties();
1586 }
1587
1588 /**
1589 * Copy object's comments to NXCP message
1590 */
1591 void NetObj::commentsToMessage(NXCPMessage *pMsg)
1592 {
1593 lockProperties();
1594 pMsg->setField(VID_COMMENTS, CHECK_NULL_EX(m_comments));
1595 unlockProperties();
1596 }
1597
1598 /**
1599 * Load trusted nodes list from database
1600 */
1601 bool NetObj::loadTrustedNodes(DB_HANDLE hdb)
1602 {
1603 DB_RESULT hResult;
1604 TCHAR query[256];
1605 int i, count;
1606
1607 _sntprintf(query, 256, _T("SELECT target_node_id FROM trusted_nodes WHERE source_object_id=%d"), m_id);
1608 hResult = DBSelect(hdb, query);
1609 if (hResult != NULL)
1610 {
1611 count = DBGetNumRows(hResult);
1612 if (count > 0)
1613 {
1614 m_dwNumTrustedNodes = count;
1615 m_pdwTrustedNodes = (UINT32 *)malloc(sizeof(UINT32) * count);
1616 for(i = 0; i < count; i++)
1617 {
1618 m_pdwTrustedNodes[i] = DBGetFieldULong(hResult, i, 0);
1619 }
1620 }
1621 DBFreeResult(hResult);
1622 }
1623 return (hResult != NULL);
1624 }
1625
1626 /**
1627 * Save list of trusted nodes to database
1628 */
1629 bool NetObj::saveTrustedNodes(DB_HANDLE hdb)
1630 {
1631 TCHAR query[256];
1632 UINT32 i;
1633 bool rc = false;
1634
1635 _sntprintf(query, 256, _T("DELETE FROM trusted_nodes WHERE source_object_id=%d"), m_id);
1636 if (DBQuery(hdb, query))
1637 {
1638 for(i = 0; i < m_dwNumTrustedNodes; i++)
1639 {
1640 _sntprintf(query, 256, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"),
1641 m_id, m_pdwTrustedNodes[i]);
1642 if (!DBQuery(hdb, query))
1643 break;
1644 }
1645 if (i == m_dwNumTrustedNodes)
1646 rc = true;
1647 }
1648 return rc;
1649 }
1650
1651 /**
1652 * Check if given node is in trust list
1653 * Will always return TRUE if system parameter CheckTrustedNodes set to 0
1654 */
1655 bool NetObj::isTrustedNode(UINT32 id)
1656 {
1657 bool rc;
1658
1659 if (g_flags & AF_CHECK_TRUSTED_NODES)
1660 {
1661 UINT32 i;
1662
1663 lockProperties();
1664 for(i = 0, rc = false; i < m_dwNumTrustedNodes; i++)
1665 {
1666 if (m_pdwTrustedNodes[i] == id)
1667 {
1668 rc = true;
1669 break;
1670 }
1671 }
1672 unlockProperties();
1673 }
1674 else
1675 {
1676 rc = true;
1677 }
1678 return rc;
1679 }
1680
1681 /**
1682 * Get list of parent objects for NXSL script
1683 */
1684 NXSL_Array *NetObj::getParentsForNXSL()
1685 {
1686 NXSL_Array *parents = new NXSL_Array;
1687 int index = 0;
1688
1689 lockParentList(false);
1690 for(int i = 0; i < m_parentList->size(); i++)
1691 {
1692 NetObj *obj = m_parentList->get(i);
1693 if ((obj->getObjectClass() == OBJECT_CONTAINER) ||
1694 (obj->getObjectClass() == OBJECT_SERVICEROOT) ||
1695 (obj->getObjectClass() == OBJECT_NETWORK))
1696 {
1697 parents->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, obj)));
1698 }
1699 }
1700 unlockParentList();
1701
1702 return parents;
1703 }
1704
1705 /**
1706 * Get list of child objects for NXSL script
1707 */
1708 NXSL_Array *NetObj::getChildrenForNXSL()
1709 {
1710 NXSL_Array *children = new NXSL_Array;
1711 int index = 0;
1712
1713 lockChildList(false);
1714 for(int i = 0; i < m_childList->size(); i++)
1715 {
1716 NetObj *obj = m_childList->get(i);
1717 if (obj->getObjectClass() == OBJECT_NODE)
1718 {
1719 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, obj)));
1720 }
1721 else if (obj->getObjectClass() == OBJECT_INTERFACE)
1722 {
1723 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, obj)));
1724 }
1725 else
1726 {
1727 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, obj)));
1728 }
1729 }
1730 unlockChildList();
1731
1732 return children;
1733 }
1734
1735 /**
1736 * Get full list of child objects (including both direct and indirect childs)
1737 */
1738 void NetObj::getFullChildListInternal(ObjectIndex *list, bool eventSourceOnly)
1739 {
1740 lockChildList(false);
1741 for(int i = 0; i < m_childList->size(); i++)
1742 {
1743 NetObj *obj = m_childList->get(i);
1744 if (!eventSourceOnly || IsEventSource(obj->getObjectClass()))
1745 list->put(obj->getId(), obj);
1746 obj->getFullChildListInternal(list, eventSourceOnly);
1747 }
1748 unlockChildList();
1749 }
1750
1751 /**
1752 * Get full list of child objects (including both direct and indirect childs).
1753 * Returned array is dynamically allocated and must be deleted by the caller.
1754 *
1755 * @param eventSourceOnly if true, only objects that can be event source will be included
1756 */
1757 ObjectArray<NetObj> *NetObj::getFullChildList(bool eventSourceOnly, bool updateRefCount)
1758 {
1759 ObjectIndex list;
1760 getFullChildListInternal(&list, eventSourceOnly);
1761 return list.getObjects(updateRefCount);
1762 }
1763
1764 /**
1765 * Get list of child objects (direct only). Returned array is
1766 * dynamically allocated and must be deleted by the caller.
1767 *
1768 * @param typeFilter Only return objects with class ID equals given value.
1769 * Set to -1 to disable filtering.
1770 */
1771 ObjectArray<NetObj> *NetObj::getChildList(int typeFilter)
1772 {
1773 lockChildList(false);
1774 ObjectArray<NetObj> *list = new ObjectArray<NetObj>((int)m_childList->size(), 16, false);
1775 for(int i = 0; i < m_childList->size(); i++)
1776 {
1777 if ((typeFilter == -1) || (typeFilter == m_childList->get(i)->getObjectClass()))
1778 list->add(m_childList->get(i));
1779 }
1780 unlockChildList();
1781 return list;
1782 }
1783
1784 /**
1785 * Get list of parent objects (direct only). Returned array is
1786 * dynamically allocated and must be deleted by the caller.
1787 *
1788 * @param typeFilter Only return objects with class ID equals given value.
1789 * Set to -1 to disable filtering.
1790 */
1791 ObjectArray<NetObj> *NetObj::getParentList(int typeFilter)
1792 {
1793 lockParentList(false);
1794 ObjectArray<NetObj> *list = new ObjectArray<NetObj>(m_parentList->size(), 16, false);
1795 for(int i = 0; i < m_parentList->size(); i++)
1796 {
1797 if ((typeFilter == -1) || (typeFilter == m_parentList->get(i)->getObjectClass()))
1798 list->add(m_parentList->get(i));
1799 }
1800 unlockParentList();
1801 return list;
1802 }
1803
1804 /**
1805 * FInd child object by name (with optional class filter)
1806 */
1807 NetObj *NetObj::findChildObject(const TCHAR *name, int typeFilter)
1808 {
1809 NetObj *object = NULL;
1810 lockChildList(false);
1811 for(int i = 0; i < m_childList->size(); i++)
1812 {
1813 NetObj *o = m_childList->get(i);
1814 if (((typeFilter == -1) || (typeFilter == o->getObjectClass())) && !_tcsicmp(name, o->getName()))
1815 {
1816 object = o;
1817 break;
1818 }
1819 }
1820 unlockChildList();
1821 return object;
1822 }
1823
1824 /**
1825 * Called by client session handler to check if threshold summary should
1826 * be shown for this object. Default implementation always returns false.
1827 */
1828 bool NetObj::showThresholdSummary()
1829 {
1830 return false;
1831 }
1832
1833 /**
1834 * Must return true if object is a possible event source
1835 */
1836 bool NetObj::isEventSource()
1837 {
1838 return false;
1839 }
1840
1841 /**
1842 * Must return true if object is a possible data collection target
1843 */
1844 bool NetObj::isDataCollectionTarget()
1845 {
1846 return false;
1847 }
1848
1849 /**
1850 * Get module data
1851 */
1852 ModuleData *NetObj::getModuleData(const TCHAR *module)
1853 {
1854 lockProperties();
1855 ModuleData *data = (m_moduleData != NULL) ? m_moduleData->get(module) : NULL;
1856 unlockProperties();
1857 return data;
1858 }
1859
1860 /**
1861 * Set module data
1862 */
1863 void NetObj::setModuleData(const TCHAR *module, ModuleData *data)
1864 {
1865 lockProperties();
1866 if (m_moduleData == NULL)
1867 m_moduleData = new StringObjectMap<ModuleData>(true);
1868 m_moduleData->set(module, data);
1869 unlockProperties();
1870 }
1871
1872 /**
1873 * Add new location entry
1874 */
1875 void NetObj::addLocationToHistory()
1876 {
1877 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1878 UINT32 startTimestamp;
1879 bool isSamePlace;
1880 DB_RESULT hResult;
1881 if (!isLocationTableExists())
1882 {
1883 DbgPrintf(4, _T("NetObj::addLocationToHistory: Geolocation history table will be created for object %s [%d]"), m_name, m_id);
1884 if (!createLocationHistoryTable(hdb))
1885 {
1886 DbgPrintf(4, _T("NetObj::addLocationToHistory: Error creating geolocation history table for object %s [%d]"), m_name, m_id);
1887 return;
1888 }
1889 }
1890 const TCHAR *query;
1891 switch(g_dbSyntax)
1892 {
1893 case DB_SYNTAX_ORACLE:
1894 query = _T("SELECT * FROM (SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC) WHERE ROWNUM<=1");
1895 break;
1896 case DB_SYNTAX_MSSQL:
1897 query = _T("SELECT TOP 1 latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC");
1898 break;
1899 case DB_SYNTAX_DB2:
1900 query = _T("SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC FETCH FIRST 200 ROWS ONLY");
1901 break;
1902 default:
1903 query = _T("SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC LIMIT 1");
1904 break;
1905 }
1906 TCHAR preparedQuery[256];
1907 _sntprintf(preparedQuery, 256, query, m_id);
1908 DB_STATEMENT hStmt = DBPrepare(hdb, preparedQuery);
1909
1910 if (hStmt == NULL)
1911 goto onFail;
1912
1913 hResult = DBSelectPrepared(hStmt);
1914 if (hResult == NULL)
1915 goto onFail;
1916 if (DBGetNumRows(hResult) > 0)
1917 {
1918 startTimestamp = DBGetFieldULong(hResult, 0, 3);
1919 isSamePlace = m_geoLocation.sameLocation(DBGetFieldDouble(hResult, 0, 0), DBGetFieldDouble(hResult, 0, 1), DBGetFieldLong(hResult, 0, 2));
1920 DBFreeStatement(hStmt);
1921 DBFreeResult(hResult);
1922 }
1923 else
1924 {
1925 isSamePlace = false;
1926 }
1927
1928 if (isSamePlace)
1929 {
1930 TCHAR query[256];
1931 _sntprintf(query, 255, _T("UPDATE gps_history_%d SET end_timestamp = ? WHERE start_timestamp =? "), m_id);
1932 hStmt = DBPrepare(hdb, query);
1933 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
1934 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, startTimestamp);
1935 }
1936 else
1937 {
1938 TCHAR query[256];
1939 _sntprintf(query, 255, _T("INSERT INTO gps_history_%d (latitude,longitude,")
1940 _T("accuracy,start_timestamp,end_timestamp) VALUES (?,?,?,?,?)"), m_id);
1941 hStmt = DBPrepare(hdb, query);
1942
1943 TCHAR lat[32], lon[32];
1944 _sntprintf(lat, 32, _T("%f"), m_geoLocation.getLatitude());
1945 _sntprintf(lon, 32, _T("%f"), m_geoLocation.getLongitude());
1946
1947 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, lat, DB_BIND_STATIC);
1948 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, lon, DB_BIND_STATIC);
1949 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getAccuracy());
1950 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
1951 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
1952 }
1953
1954 if (hStmt == NULL)
1955 goto onFail;
1956
1957 DBExecute(hStmt);
1958 DBFreeStatement(hStmt);
1959 DBConnectionPoolReleaseConnection(hdb);
1960 return;
1961
1962 onFail:
1963 DBFreeStatement(hStmt);
1964 DbgPrintf(4, _T("NetObj::addLocationToHistory(%s [%d]): Failed to add location to history"), m_name, m_id);
1965 DBConnectionPoolReleaseConnection(hdb);
1966 return;
1967 }
1968
1969 /**
1970 * Check if given data table exist
1971 */
1972 bool NetObj::isLocationTableExists()
1973 {
1974 TCHAR table[256];
1975 _sntprintf(table, 256, _T("gps_history_%d"), m_id);
1976 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1977 int rc = DBIsTableExist(hdb, table);
1978 if (rc == DBIsTableExist_Failure)
1979 {
1980 _tprintf(_T("WARNING: call to DBIsTableExist(\"%s\") failed\n"), table);
1981 }
1982 DBConnectionPoolReleaseConnection(hdb);
1983 return rc != DBIsTableExist_NotFound;
1984 }
1985
1986 /**
1987 * Create table for storing geolocation history for this object
1988 */
1989 bool NetObj::createLocationHistoryTable(DB_HANDLE hdb)
1990 {
1991 TCHAR szQuery[256], szQueryTemplate[256];
1992 MetaDataReadStr(_T("LocationHistory"), szQueryTemplate, 255, _T(""));
1993 _sntprintf(szQuery, 256, szQueryTemplate, m_id);
1994 if (!DBQuery(hdb, szQuery))
1995 return false;
1996
1997 return true;
1998 }
1999
2000 /**
2001 * Set status calculation method
2002 */
2003 void NetObj::setStatusCalculation(int method, int arg1, int arg2, int arg3, int arg4)
2004 {
2005 lockProperties();
2006 m_statusCalcAlg = method;
2007 switch(method)
2008 {
2009 case SA_CALCULATE_SINGLE_THRESHOLD:
2010 m_statusSingleThreshold = arg1;
2011 break;
2012 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
2013 m_statusThresholds[0] = arg1;
2014 m_statusThresholds[1] = arg2;
2015 m_statusThresholds[2] = arg3;
2016 m_statusThresholds[3] = arg4;
2017 break;
2018 default:
2019 break;
2020 }
2021 setModified();
2022 unlockProperties();
2023 }
2024
2025 /**
2026 * Set status propagation method
2027 */
2028 void NetObj::setStatusPropagation(int method, int arg1, int arg2, int arg3, int arg4)
2029 {
2030 lockProperties();
2031 m_statusPropAlg = method;
2032 switch(method)
2033 {
2034 case SA_PROPAGATE_FIXED:
2035 m_fixedStatus = arg1;
2036 break;
2037 case SA_PROPAGATE_RELATIVE:
2038 m_statusShift = arg1;
2039 break;
2040 case SA_PROPAGATE_TRANSLATED:
2041 m_statusTranslation[0] = arg1;
2042 m_statusTranslation[1] = arg2;
2043 m_statusTranslation[2] = arg3;
2044 m_statusTranslation[3] = arg4;
2045 break;
2046 default:
2047 break;
2048 }
2049 setModified();
2050 unlockProperties();
2051 }
2052
2053 /**
2054 * Enter maintenance mode
2055 */
2056 void NetObj::enterMaintenanceMode()
2057 {
2058 DbgPrintf(4, _T("Entering maintenance mode for object %s [%d] (%s)"), m_name, m_id, getObjectClassName());
2059
2060 lockChildList(false);
2061 for(int i = 0; i < m_childList->size(); i++)
2062 {
2063 NetObj *object = m_childList->get(i);
2064 if (object->getStatus() != STATUS_UNMANAGED)
2065 object->enterMaintenanceMode();
2066 }
2067 unlockChildList();
2068 }
2069
2070 /**
2071 * Leave maintenance mode
2072 */
2073 void NetObj::leaveMaintenanceMode()
2074 {
2075 DbgPrintf(4, _T("Leaving maintenance mode for object %s [%d] (%s)"), m_name, m_id, getObjectClassName());
2076
2077 lockChildList(false);
2078 for(int i = 0; i < m_childList->size(); i++)
2079 {
2080 NetObj *object = m_childList->get(i);
2081 if (object->getStatus() != STATUS_UNMANAGED)
2082 object->leaveMaintenanceMode();
2083 }
2084 unlockChildList();
2085 }
2086
2087 /**
2088 * Get all custom attributes as NXSL hash map
2089 */
2090 NXSL_Value *NetObj::getCustomAttributesForNXSL() const
2091 {
2092 NXSL_HashMap *map = new NXSL_HashMap();
2093 lockProperties();
2094 StructArray<KeyValuePair> *attributes = m_customAttributes.toArray();
2095 for(int i = 0; i < attributes->size(); i++)
2096 {
2097 KeyValuePair *p = attributes->get(i);
2098 map->set(p->key, new NXSL_Value((const TCHAR *)p->value));
2099 }
2100 unlockProperties();
2101 delete attributes;
2102 return new NXSL_Value(map);
2103 }
2104
2105 /**
2106 * Create NXSL object for this object
2107 */
2108 NXSL_Value *NetObj::createNXSLObject()
2109 {
2110 return new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, this));
2111 }