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