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