2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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.
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.
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.
28 static const TCHAR
*s_className
[]=
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")
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
;
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
;
77 m_statusSingleThreshold
= 75;
79 for(i
= 0; i
< 4; i
++)
81 m_statusTranslation
[i
] = i
+ 1;
82 m_statusThresholds
[i
] = 80 - i
* 20;
86 m_postalAddress
= new PostalAddress();
87 m_dashboards
= new IntegerArray
<UINT32
>();
95 MutexDestroy(m_mutexProperties
);
96 MutexDestroy(m_mutexRefCount
);
97 MutexDestroy(m_mutexACL
);
98 RWLockDestroy(m_rwlockParentList
);
99 RWLockDestroy(m_rwlockChildList
);
103 safe_free(m_pdwTrustedNodes
);
104 safe_free(m_comments
);
106 delete m_postalAddress
;
111 * Get class name for this object
113 const TCHAR
*NetObj::getObjectClassName() const
115 int c
= getObjectClass();
116 return ((c
>= 0) && (c
< sizeof(s_className
) / sizeof(const TCHAR
*))) ? s_className
[c
] : _T("Custom");
120 * Get class name for given class ID
122 const TCHAR
*NetObj::getObjectClassName(int objectClass
)
124 return ((objectClass
>= 0) && (objectClass
< sizeof(s_className
) / sizeof(const TCHAR
*))) ? s_className
[objectClass
] : _T("Custom");
128 * Create object from database data
130 bool NetObj::loadFromDatabase(DB_HANDLE hdb
, UINT32 dwId
)
132 return false; // Abstract objects cannot be loaded from database
136 * Link related objects after loading from database
138 void NetObj::linkObjects()
143 * Save object to database
145 BOOL
NetObj::saveToDatabase(DB_HANDLE hdb
)
147 return FALSE
; // Abstract objects cannot be saved to database
151 * Parameters for DeleteModuleDataCallback and SaveModuleDataCallback
153 struct ModuleDataDatabaseCallbackParams
160 * Callback for deleting module data from database
162 static EnumerationCallbackResult
DeleteModuleDataCallback(const TCHAR
*key
, const void *value
, void *data
)
164 return ((ModuleData
*)value
)->deleteFromDatabase(((ModuleDataDatabaseCallbackParams
*)data
)->hdb
, ((ModuleDataDatabaseCallbackParams
*)data
)->id
) ? _CONTINUE
: _STOP
;
168 * Delete object from database
170 bool NetObj::deleteFromDatabase(DB_HANDLE hdb
)
173 bool success
= executeQueryOnObject(hdb
, _T("DELETE FROM acl WHERE object_id=?"));
175 success
= executeQueryOnObject(hdb
, _T("DELETE FROM object_properties WHERE object_id=?"));
177 success
= executeQueryOnObject(hdb
, _T("DELETE FROM object_custom_attributes WHERE object_id=?"));
180 if (success
&& ConfigReadInt(_T("DeleteEventsOfDeletedObject"), 1))
182 success
= executeQueryOnObject(hdb
, _T("DELETE FROM event_log WHERE event_source=?"));
186 if (success
&& ConfigReadInt(_T("DeleteAlarmsOfDeletedObject"), 1))
188 success
= DeleteObjectAlarms(m_id
, hdb
);
191 // Delete module data
192 if (success
&& (m_moduleData
!= NULL
))
194 ModuleDataDatabaseCallbackParams data
;
197 success
= (m_moduleData
->forEach(DeleteModuleDataCallback
, &data
) == _CONTINUE
);
204 * Load common object properties from database
206 bool NetObj::loadCommonProperties(DB_HANDLE hdb
)
208 bool success
= false;
210 // Load access options
211 DB_STATEMENT hStmt
= DBPrepare(hdb
,
212 _T("SELECT name,status,is_deleted,")
213 _T("inherit_access_rights,last_modified,status_calc_alg,")
214 _T("status_prop_alg,status_fixed_val,status_shift,")
215 _T("status_translation,status_single_threshold,")
216 _T("status_thresholds,comments,is_system,")
217 _T("location_type,latitude,longitude,location_accuracy,")
218 _T("location_timestamp,guid,image,submap_id,country,city,")
219 _T("street_address,postcode,maint_mode,maint_event_id FROM object_properties ")
220 _T("WHERE object_id=?"));
223 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
224 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
227 if (DBGetNumRows(hResult
) > 0)
229 DBGetField(hResult
, 0, 0, m_name
, MAX_OBJECT_NAME
);
230 m_status
= DBGetFieldLong(hResult
, 0, 1);
231 m_isDeleted
= DBGetFieldLong(hResult
, 0, 2) ? true : false;
232 m_inheritAccessRights
= DBGetFieldLong(hResult
, 0, 3) ? true : false;
233 m_dwTimeStamp
= DBGetFieldULong(hResult
, 0, 4);
234 m_statusCalcAlg
= DBGetFieldLong(hResult
, 0, 5);
235 m_statusPropAlg
= DBGetFieldLong(hResult
, 0, 6);
236 m_fixedStatus
= DBGetFieldLong(hResult
, 0, 7);
237 m_statusShift
= DBGetFieldLong(hResult
, 0, 8);
238 DBGetFieldByteArray(hResult
, 0, 9, m_statusTranslation
, 4, STATUS_WARNING
);
239 m_statusSingleThreshold
= DBGetFieldLong(hResult
, 0, 10);
240 DBGetFieldByteArray(hResult
, 0, 11, m_statusThresholds
, 4, 50);
241 safe_free(m_comments
);
242 m_comments
= DBGetField(hResult
, 0, 12, NULL
, 0);
243 m_isSystem
= DBGetFieldLong(hResult
, 0, 13) ? true : false;
245 int locType
= DBGetFieldLong(hResult
, 0, 14);
246 if (locType
!= GL_UNSET
)
248 TCHAR lat
[32], lon
[32];
250 DBGetField(hResult
, 0, 15, lat
, 32);
251 DBGetField(hResult
, 0, 16, lon
, 32);
252 m_geoLocation
= GeoLocation(locType
, lat
, lon
, DBGetFieldLong(hResult
, 0, 17), DBGetFieldULong(hResult
, 0, 18));
256 m_geoLocation
= GeoLocation();
259 m_guid
= DBGetFieldGUID(hResult
, 0, 19);
260 m_image
= DBGetFieldGUID(hResult
, 0, 20);
261 m_submapId
= DBGetFieldULong(hResult
, 0, 21);
263 TCHAR country
[64], city
[64], streetAddress
[256], postcode
[32];
264 DBGetField(hResult
, 0, 22, country
, 64);
265 DBGetField(hResult
, 0, 23, city
, 64);
266 DBGetField(hResult
, 0, 24, streetAddress
, 256);
267 DBGetField(hResult
, 0, 25, postcode
, 32);
268 delete m_postalAddress
;
269 m_postalAddress
= new PostalAddress(country
, city
, streetAddress
, postcode
);
271 m_maintenanceMode
= DBGetFieldLong(hResult
, 0, 26) ? true : false;
272 m_maintenanceEventId
= DBGetFieldUInt64(hResult
, 0, 27);
276 DBFreeResult(hResult
);
278 DBFreeStatement(hStmt
);
281 // Load custom attributes
284 hStmt
= DBPrepare(hdb
, _T("SELECT attr_name,attr_value FROM object_custom_attributes WHERE object_id=?"));
287 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
288 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
294 count
= DBGetNumRows(hResult
);
295 for(i
= 0; i
< count
; i
++)
297 name
= DBGetField(hResult
, i
, 0, NULL
, 0);
300 value
= DBGetField(hResult
, i
, 1, NULL
, 0);
303 m_customAttributes
.setPreallocated(name
, value
);
307 DBFreeResult(hResult
);
313 DBFreeStatement(hStmt
);
321 // Load associated dashboards
324 hStmt
= DBPrepare(hdb
, _T("SELECT dashboard_id FROM dashboard_associations WHERE object_id=?"));
327 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
328 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
331 int count
= DBGetNumRows(hResult
);
332 for(int i
= 0; i
< count
; i
++)
334 m_dashboards
->add(DBGetFieldULong(hResult
, i
, 0));
336 DBFreeResult(hResult
);
342 DBFreeStatement(hStmt
);
351 success
= loadTrustedNodes(hdb
);
354 DbgPrintf(4, _T("NetObj::loadCommonProperties() failed for object %s [%ld] class=%d"), m_name
, (long)m_id
, getObjectClass());
360 * Callback for saving custom attribute in database
362 static EnumerationCallbackResult
SaveAttributeCallback(const TCHAR
*key
, const void *value
, void *data
)
364 DB_STATEMENT hStmt
= (DB_STATEMENT
)data
;
365 DBBind(hStmt
, 2, DB_SQLTYPE_VARCHAR
, key
, DB_BIND_STATIC
);
366 DBBind(hStmt
, 3, DB_SQLTYPE_VARCHAR
, (const TCHAR
*)value
, DB_BIND_STATIC
);
367 return DBExecute(hStmt
) ? _CONTINUE
: _STOP
;
371 * Callback for saving module data in database
373 static EnumerationCallbackResult
SaveModuleDataCallback(const TCHAR
*key
, const void *value
, void *data
)
375 return ((ModuleData
*)value
)->saveToDatabase(((ModuleDataDatabaseCallbackParams
*)data
)->hdb
, ((ModuleDataDatabaseCallbackParams
*)data
)->id
) ? _CONTINUE
: _STOP
;
379 * Save common object properties to database
381 bool NetObj::saveCommonProperties(DB_HANDLE hdb
)
384 if (IsDatabaseRecordExist(hdb
, _T("object_properties"), _T("object_id"), m_id
))
386 hStmt
= DBPrepare(hdb
,
387 _T("UPDATE object_properties SET name=?,status=?,")
388 _T("is_deleted=?,inherit_access_rights=?,")
389 _T("last_modified=?,status_calc_alg=?,status_prop_alg=?,")
390 _T("status_fixed_val=?,status_shift=?,status_translation=?,")
391 _T("status_single_threshold=?,status_thresholds=?,")
392 _T("comments=?,is_system=?,location_type=?,latitude=?,")
393 _T("longitude=?,location_accuracy=?,location_timestamp=?,")
394 _T("guid=?,image=?,submap_id=?,country=?,city=?,")
395 _T("street_address=?,postcode=?,maint_mode=?,maint_event_id=? WHERE object_id=?"));
399 hStmt
= DBPrepare(hdb
,
400 _T("INSERT INTO object_properties (name,status,is_deleted,")
401 _T("inherit_access_rights,last_modified,status_calc_alg,")
402 _T("status_prop_alg,status_fixed_val,status_shift,status_translation,")
403 _T("status_single_threshold,status_thresholds,comments,is_system,")
404 _T("location_type,latitude,longitude,location_accuracy,location_timestamp,")
405 _T("guid,image,submap_id,country,city,street_address,postcode,maint_mode,")
406 _T("maint_event_id,object_id) ")
407 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
412 TCHAR szTranslation
[16], szThresholds
[16], lat
[32], lon
[32];
413 for(int i
= 0, j
= 0; i
< 4; i
++, j
+= 2)
415 _sntprintf(&szTranslation
[j
], 16 - j
, _T("%02X"), (BYTE
)m_statusTranslation
[i
]);
416 _sntprintf(&szThresholds
[j
], 16 - j
, _T("%02X"), (BYTE
)m_statusThresholds
[i
]);
418 _sntprintf(lat
, 32, _T("%f"), m_geoLocation
.getLatitude());
419 _sntprintf(lon
, 32, _T("%f"), m_geoLocation
.getLongitude());
421 DBBind(hStmt
, 1, DB_SQLTYPE_VARCHAR
, m_name
, DB_BIND_STATIC
);
422 DBBind(hStmt
, 2, DB_SQLTYPE_INTEGER
, (LONG
)m_status
);
423 DBBind(hStmt
, 3, DB_SQLTYPE_INTEGER
, (LONG
)(m_isDeleted
? 1 : 0));
424 DBBind(hStmt
, 4, DB_SQLTYPE_INTEGER
, (LONG
)(m_inheritAccessRights
? 1 : 0));
425 DBBind(hStmt
, 5, DB_SQLTYPE_INTEGER
, (LONG
)m_dwTimeStamp
);
426 DBBind(hStmt
, 6, DB_SQLTYPE_INTEGER
, (LONG
)m_statusCalcAlg
);
427 DBBind(hStmt
, 7, DB_SQLTYPE_INTEGER
, (LONG
)m_statusPropAlg
);
428 DBBind(hStmt
, 8, DB_SQLTYPE_INTEGER
, (LONG
)m_fixedStatus
);
429 DBBind(hStmt
, 9, DB_SQLTYPE_INTEGER
, (LONG
)m_statusShift
);
430 DBBind(hStmt
, 10, DB_SQLTYPE_VARCHAR
, szTranslation
, DB_BIND_STATIC
);
431 DBBind(hStmt
, 11, DB_SQLTYPE_INTEGER
, (LONG
)m_statusSingleThreshold
);
432 DBBind(hStmt
, 12, DB_SQLTYPE_VARCHAR
, szThresholds
, DB_BIND_STATIC
);
433 DBBind(hStmt
, 13, DB_SQLTYPE_VARCHAR
, m_comments
, DB_BIND_STATIC
);
434 DBBind(hStmt
, 14, DB_SQLTYPE_INTEGER
, (LONG
)(m_isSystem
? 1 : 0));
435 DBBind(hStmt
, 15, DB_SQLTYPE_INTEGER
, (LONG
)m_geoLocation
.getType());
436 DBBind(hStmt
, 16, DB_SQLTYPE_VARCHAR
, lat
, DB_BIND_STATIC
);
437 DBBind(hStmt
, 17, DB_SQLTYPE_VARCHAR
, lon
, DB_BIND_STATIC
);
438 DBBind(hStmt
, 18, DB_SQLTYPE_INTEGER
, (LONG
)m_geoLocation
.getAccuracy());
439 DBBind(hStmt
, 19, DB_SQLTYPE_INTEGER
, (UINT32
)m_geoLocation
.getTimestamp());
440 DBBind(hStmt
, 20, DB_SQLTYPE_VARCHAR
, m_guid
);
441 DBBind(hStmt
, 21, DB_SQLTYPE_VARCHAR
, m_image
);
442 DBBind(hStmt
, 22, DB_SQLTYPE_INTEGER
, m_submapId
);
443 DBBind(hStmt
, 23, DB_SQLTYPE_VARCHAR
, m_postalAddress
->getCountry(), DB_BIND_STATIC
);
444 DBBind(hStmt
, 24, DB_SQLTYPE_VARCHAR
, m_postalAddress
->getCity(), DB_BIND_STATIC
);
445 DBBind(hStmt
, 25, DB_SQLTYPE_VARCHAR
, m_postalAddress
->getStreetAddress(), DB_BIND_STATIC
);
446 DBBind(hStmt
, 26, DB_SQLTYPE_VARCHAR
, m_postalAddress
->getPostCode(), DB_BIND_STATIC
);
447 DBBind(hStmt
, 27, DB_SQLTYPE_VARCHAR
, m_maintenanceMode
? _T("1") : _T("0"), DB_BIND_STATIC
);
448 DBBind(hStmt
, 28, DB_SQLTYPE_BIGINT
, m_maintenanceEventId
);
449 DBBind(hStmt
, 29, DB_SQLTYPE_INTEGER
, m_id
);
451 bool success
= DBExecute(hStmt
);
452 DBFreeStatement(hStmt
);
454 // Save custom attributes
458 _sntprintf(szQuery
, 512, _T("DELETE FROM object_custom_attributes WHERE object_id=%d"), m_id
);
459 success
= DBQuery(hdb
, szQuery
);
462 hStmt
= DBPrepare(hdb
, _T("INSERT INTO object_custom_attributes (object_id,attr_name,attr_value) VALUES (?,?,?)"));
465 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
466 success
= (m_customAttributes
.forEach(SaveAttributeCallback
, hStmt
) == _CONTINUE
);
467 DBFreeStatement(hStmt
);
476 // Save dashboard associations
480 _sntprintf(szQuery
, 512, _T("DELETE FROM dashboard_associations WHERE object_id=%d"), m_id
);
481 success
= DBQuery(hdb
, szQuery
);
482 if (success
&& (m_dashboards
->size() > 0))
484 hStmt
= DBPrepare(hdb
, _T("INSERT INTO dashboard_associations (object_id,dashboard_id) VALUES (?,?)"));
487 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
488 for(int i
= 0; (i
< m_dashboards
->size()) && success
; i
++)
490 DBBind(hStmt
, 2, DB_SQLTYPE_INTEGER
, m_dashboards
->get(i
));
491 success
= DBExecute(hStmt
);
493 DBFreeStatement(hStmt
);
503 if (success
&& (m_moduleData
!= NULL
))
505 ModuleDataDatabaseCallbackParams data
;
508 success
= (m_moduleData
->forEach(SaveModuleDataCallback
, &data
) == _CONTINUE
);
512 success
= saveTrustedNodes(hdb
);
518 * Add reference to the new child object
520 void NetObj::addChild(NetObj
*object
)
523 if (m_childList
->contains(object
))
526 return; // Already in the child list
528 m_childList
->add(object
);
532 DbgPrintf(7, _T("NetObj::addChild: this=%s [%d]; object=%s [%d]"), m_name
, m_id
, object
->m_name
, object
->m_id
);
536 * Add reference to parent object
538 void NetObj::addParent(NetObj
*object
)
540 lockParentList(true);
541 if (m_parentList
->contains(object
))
544 return; // Already in the parents list
546 m_parentList
->add(object
);
550 DbgPrintf(7, _T("NetObj::addParent: this=%s [%d]; object=%s [%d]"), m_name
, m_id
, object
->m_name
, object
->m_id
);
554 * Delete reference to child object
556 void NetObj::deleteChild(NetObj
*object
)
561 for(i
= 0; i
< m_childList
->size(); i
++)
562 if (m_childList
->get(i
) == object
)
565 if (i
== m_childList
->size()) // No such object
571 DbgPrintf(7, _T("NetObj::deleteChild: this=%s [%d]; object=%s [%d]"), m_name
, m_id
, object
->m_name
, object
->m_id
);
572 m_childList
->remove(i
);
579 * Delete reference to parent object
581 void NetObj::deleteParent(NetObj
*object
)
585 lockParentList(true);
586 for(i
= 0; i
< m_parentList
->size(); i
++)
587 if (m_parentList
->get(i
) == object
)
589 if (i
== m_parentList
->size()) // No such object
595 DbgPrintf(7, _T("NetObj::deleteParent: this=%s [%d]; object=%s [%d]"), m_name
, m_id
, object
->m_name
, object
->m_id
);
597 m_parentList
->remove(i
);
604 * Walker callback to call OnObjectDelete for each active object
606 void NetObj::onObjectDeleteCallback(NetObj
*object
, void *data
)
608 UINT32 currId
= ((NetObj
*)data
)->getId();
609 if ((object
->getId() != currId
) && !object
->isDeleted())
610 object
->onObjectDelete(currId
);
614 * Prepare object for deletion - remove all references, etc.
616 * @param initiator pointer to parent object which causes recursive deletion or NULL
618 void NetObj::deleteObject(NetObj
*initiator
)
620 DbgPrintf(4, _T("Deleting object %d [%s]"), m_id
, m_name
);
622 // Prevent object change propagation until it's marked as deleted
623 // (to prevent the object's incorrect appearance in GUI
628 // Notify modules about object deletion
629 CALL_ALL_MODULES(pfPreObjectDelete
, (this));
631 prepareForDeletion();
633 DbgPrintf(5, _T("NetObj::deleteObject(): deleting object %d from indexes"), m_id
);
634 NetObjDeleteFromIndexes(this);
636 // Delete references to this object from child objects
637 DbgPrintf(5, _T("NetObj::deleteObject(): clearing child list for object %d"), m_id
);
638 ObjectArray
<NetObj
> *deleteList
= NULL
;
640 for(int i
= 0; i
< m_childList
->size(); i
++)
642 NetObj
*o
= m_childList
->get(i
);
643 if (o
->getParentCount() == 1)
645 // last parent, delete object
646 if (deleteList
== NULL
)
647 deleteList
= new ObjectArray
<NetObj
>(16, 16, false);
652 o
->deleteParent(this);
656 m_childList
->clear();
659 // Delete orphaned child objects
660 if (deleteList
!= NULL
)
662 for(int i
= 0; i
< deleteList
->size(); i
++)
664 NetObj
*obj
= deleteList
->get(i
);
665 DbgPrintf(5, _T("NetObj::deleteObject(): calling deleteObject() on %s [%d]"), obj
->getName(), obj
->getId());
666 obj
->deleteObject(this);
671 // Remove references to this object from parent objects
672 DbgPrintf(5, _T("NetObj::Delete(): clearing parent list for object %d"), m_id
);
673 lockParentList(true);
674 for(int i
= 0; i
< m_parentList
->size(); i
++)
676 // If parent is deletion initiator then this object already
677 // removed from parent's list
678 NetObj
*obj
= m_parentList
->get(i
);
679 if (obj
!= initiator
)
681 obj
->deleteChild(this);
682 obj
->calculateCompoundStatus();
686 m_parentList
->clear();
695 // Notify all other objects about object deletion
696 DbgPrintf(5, _T("NetObj::deleteObject(): calling onObjectDelete(%d)"), m_id
);
697 g_idxObjectById
.forEach(onObjectDeleteCallback
, this);
699 DbgPrintf(4, _T("Object %d successfully deleted"), m_id
);
703 * Default handler for object deletion notification
705 void NetObj::onObjectDelete(UINT32 dwObjectId
)
710 * Get childs IDs in printable form
712 const TCHAR
*NetObj::dbgGetChildList(TCHAR
*szBuffer
)
714 TCHAR
*pBuf
= szBuffer
;
716 lockChildList(false);
717 for(int i
= 0; i
< m_childList
->size(); i
++)
719 _sntprintf(pBuf
, 10, _T("%d "), m_childList
->get(i
)->getId());
724 if (pBuf
!= szBuffer
)
730 * Get parents IDs in printable form
732 const TCHAR
*NetObj::dbgGetParentList(TCHAR
*szBuffer
)
734 TCHAR
*pBuf
= szBuffer
;
736 lockParentList(false);
737 for(int i
= 0; i
< m_parentList
->size(); i
++)
739 _sntprintf(pBuf
, 10, _T("%d "), m_parentList
->get(i
)->getId());
744 if (pBuf
!= szBuffer
)
750 * Calculate status for compound object based on childs' status
752 void NetObj::calculateCompoundStatus(BOOL bForcedRecalc
)
754 if (m_status
== STATUS_UNMANAGED
)
757 int mostCriticalAlarm
= GetMostCriticalStatusForObject(m_id
);
758 int mostCriticalDCI
=
759 (getObjectClass() == OBJECT_NODE
|| getObjectClass() == OBJECT_MOBILEDEVICE
|| getObjectClass() == OBJECT_CLUSTER
|| getObjectClass() == OBJECT_ACCESSPOINT
) ?
760 ((DataCollectionTarget
*)this)->getMostCriticalDCIStatus() : STATUS_UNKNOWN
;
762 int oldStatus
= m_status
;
763 int mostCriticalStatus
, i
, count
, iStatusAlg
;
764 int nSingleThreshold
, *pnThresholds
;
765 int nRating
[5], iChildStatus
, nThresholds
[4];
768 if (m_statusCalcAlg
== SA_CALCULATE_DEFAULT
)
770 iStatusAlg
= GetDefaultStatusCalculation(&nSingleThreshold
, &pnThresholds
);
774 iStatusAlg
= m_statusCalcAlg
;
775 nSingleThreshold
= m_statusSingleThreshold
;
776 pnThresholds
= m_statusThresholds
;
778 if (iStatusAlg
== SA_CALCULATE_SINGLE_THRESHOLD
)
780 for(i
= 0; i
< 4; i
++)
781 nThresholds
[i
] = nSingleThreshold
;
782 pnThresholds
= nThresholds
;
787 case SA_CALCULATE_MOST_CRITICAL
:
788 lockChildList(false);
789 for(i
= 0, count
= 0, mostCriticalStatus
= -1; i
< m_childList
->size(); i
++)
791 iChildStatus
= m_childList
->get(i
)->getPropagatedStatus();
792 if ((iChildStatus
< STATUS_UNKNOWN
) &&
793 (iChildStatus
> mostCriticalStatus
))
795 mostCriticalStatus
= iChildStatus
;
799 m_status
= (count
> 0) ? mostCriticalStatus
: STATUS_UNKNOWN
;
802 case SA_CALCULATE_SINGLE_THRESHOLD
:
803 case SA_CALCULATE_MULTIPLE_THRESHOLDS
:
804 // Step 1: calculate severity raitings
805 memset(nRating
, 0, sizeof(int) * 5);
806 lockChildList(false);
807 for(i
= 0, count
= 0; i
< m_childList
->size(); i
++)
809 iChildStatus
= m_childList
->get(i
)->getPropagatedStatus();
810 if (iChildStatus
< STATUS_UNKNOWN
)
812 while(iChildStatus
>= 0)
813 nRating
[iChildStatus
--]++;
819 // Step 2: check what severity rating is above threshold
822 for(i
= 4; i
> 0; i
--)
823 if (nRating
[i
] * 100 / count
>= pnThresholds
[i
- 1])
829 m_status
= STATUS_UNKNOWN
;
833 m_status
= STATUS_UNKNOWN
;
837 // If alarms exist for object, apply alarm severity to object's status
838 if (mostCriticalAlarm
!= STATUS_UNKNOWN
)
840 if (m_status
== STATUS_UNKNOWN
)
842 m_status
= mostCriticalAlarm
;
846 m_status
= max(m_status
, mostCriticalAlarm
);
850 // If DCI status is calculated for object apply DCI object's statud
851 if (mostCriticalDCI
!= STATUS_UNKNOWN
)
853 if (m_status
== STATUS_UNKNOWN
)
855 m_status
= mostCriticalDCI
;
859 m_status
= max(m_status
, mostCriticalDCI
);
863 // Query loaded modules for object status
864 ENUMERATE_MODULES(pfCalculateObjectStatus
)
866 int moduleStatus
= g_pModuleList
[__i
].pfCalculateObjectStatus(this);
867 if (moduleStatus
!= STATUS_UNKNOWN
)
869 if (m_status
== STATUS_UNKNOWN
)
871 m_status
= moduleStatus
;
875 m_status
= max(m_status
, moduleStatus
);
882 // Cause parent object(s) to recalculate it's status
883 if ((oldStatus
!= m_status
) || bForcedRecalc
)
885 lockParentList(false);
886 for(i
= 0; i
< m_parentList
->size(); i
++)
887 m_parentList
->get(i
)->calculateCompoundStatus();
896 * Load ACL from database
898 bool NetObj::loadACLFromDB(DB_HANDLE hdb
)
900 bool success
= false;
902 DB_STATEMENT hStmt
= DBPrepare(hdb
, _T("SELECT user_id,access_rights FROM acl WHERE object_id=?"));
905 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
906 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
909 int count
= DBGetNumRows(hResult
);
910 for(int i
= 0; i
< count
; i
++)
911 m_accessList
->addElement(DBGetFieldULong(hResult
, i
, 0), DBGetFieldULong(hResult
, i
, 1));
912 DBFreeResult(hResult
);
915 DBFreeStatement(hStmt
);
921 * ACL enumeration parameters structure
930 * Handler for ACL elements enumeration
932 static void EnumerationHandler(UINT32 dwUserId
, UINT32 dwAccessRights
, void *pArg
)
936 _sntprintf(szQuery
, sizeof(szQuery
) / sizeof(TCHAR
), _T("INSERT INTO acl (object_id,user_id,access_rights) VALUES (%d,%d,%d)"),
937 ((SAVE_PARAM
*)pArg
)->dwObjectId
, dwUserId
, dwAccessRights
);
938 DBQuery(((SAVE_PARAM
*)pArg
)->hdb
, szQuery
);
942 * Save ACL to database
944 bool NetObj::saveACLToDB(DB_HANDLE hdb
)
947 bool success
= false;
952 _sntprintf(szQuery
, sizeof(szQuery
) / sizeof(TCHAR
), _T("DELETE FROM acl WHERE object_id=%d"), m_id
);
953 if (DBQuery(hdb
, szQuery
))
955 sp
.dwObjectId
= m_id
;
957 m_accessList
->enumerateElements(EnumerationHandler
, &sp
);
965 * Data for SendModuleDataCallback
967 struct SendModuleDataCallbackData
974 * Callback for sending module data in NXCP message
976 static EnumerationCallbackResult
SendModuleDataCallback(const TCHAR
*key
, const void *value
, void *data
)
978 ((SendModuleDataCallbackData
*)data
)->msg
->setField(((SendModuleDataCallbackData
*)data
)->id
, key
);
979 ((ModuleData
*)value
)->fillMessage(((SendModuleDataCallbackData
*)data
)->msg
, ((SendModuleDataCallbackData
*)data
)->id
+ 1);
980 ((SendModuleDataCallbackData
*)data
)->id
+= 0x100000;
985 * Fill NXCP message with object's data
986 * Object's properties are locked when this method is called. Method should not do any other locks.
987 * Data required other locks should be filled in fillMessageInternalStage2().
989 void NetObj::fillMessageInternal(NXCPMessage
*pMsg
)
991 pMsg
->setField(VID_OBJECT_CLASS
, (WORD
)getObjectClass());
992 pMsg
->setField(VID_OBJECT_ID
, m_id
);
993 pMsg
->setField(VID_GUID
, m_guid
);
994 pMsg
->setField(VID_OBJECT_NAME
, m_name
);
995 pMsg
->setField(VID_OBJECT_STATUS
, (WORD
)m_status
);
996 pMsg
->setField(VID_IS_DELETED
, (WORD
)(m_isDeleted
? 1 : 0));
997 pMsg
->setField(VID_IS_SYSTEM
, (INT16
)(m_isSystem
? 1 : 0));
998 pMsg
->setField(VID_MAINTENANCE_MODE
, (INT16
)(m_maintenanceEventId
? 1 : 0));
1000 pMsg
->setField(VID_INHERIT_RIGHTS
, m_inheritAccessRights
);
1001 pMsg
->setField(VID_STATUS_CALCULATION_ALG
, (WORD
)m_statusCalcAlg
);
1002 pMsg
->setField(VID_STATUS_PROPAGATION_ALG
, (WORD
)m_statusPropAlg
);
1003 pMsg
->setField(VID_FIXED_STATUS
, (WORD
)m_fixedStatus
);
1004 pMsg
->setField(VID_STATUS_SHIFT
, (WORD
)m_statusShift
);
1005 pMsg
->setField(VID_STATUS_TRANSLATION_1
, (WORD
)m_statusTranslation
[0]);
1006 pMsg
->setField(VID_STATUS_TRANSLATION_2
, (WORD
)m_statusTranslation
[1]);
1007 pMsg
->setField(VID_STATUS_TRANSLATION_3
, (WORD
)m_statusTranslation
[2]);
1008 pMsg
->setField(VID_STATUS_TRANSLATION_4
, (WORD
)m_statusTranslation
[3]);
1009 pMsg
->setField(VID_STATUS_SINGLE_THRESHOLD
, (WORD
)m_statusSingleThreshold
);
1010 pMsg
->setField(VID_STATUS_THRESHOLD_1
, (WORD
)m_statusThresholds
[0]);
1011 pMsg
->setField(VID_STATUS_THRESHOLD_2
, (WORD
)m_statusThresholds
[1]);
1012 pMsg
->setField(VID_STATUS_THRESHOLD_3
, (WORD
)m_statusThresholds
[2]);
1013 pMsg
->setField(VID_STATUS_THRESHOLD_4
, (WORD
)m_statusThresholds
[3]);
1014 pMsg
->setField(VID_COMMENTS
, CHECK_NULL_EX(m_comments
));
1015 pMsg
->setField(VID_IMAGE
, m_image
);
1016 pMsg
->setField(VID_SUBMAP_ID
, m_submapId
);
1017 pMsg
->setField(VID_NUM_TRUSTED_NODES
, m_dwNumTrustedNodes
);
1018 if (m_dwNumTrustedNodes
> 0)
1019 pMsg
->setFieldFromInt32Array(VID_TRUSTED_NODES
, m_dwNumTrustedNodes
, m_pdwTrustedNodes
);
1020 pMsg
->setFieldFromInt32Array(VID_DASHBOARDS
, m_dashboards
);
1022 m_customAttributes
.fillMessage(pMsg
, VID_NUM_CUSTOM_ATTRIBUTES
, VID_CUSTOM_ATTRIBUTES_BASE
);
1024 m_geoLocation
.fillMessage(*pMsg
);
1026 pMsg
->setField(VID_COUNTRY
, m_postalAddress
->getCountry());
1027 pMsg
->setField(VID_CITY
, m_postalAddress
->getCity());
1028 pMsg
->setField(VID_STREET_ADDRESS
, m_postalAddress
->getStreetAddress());
1029 pMsg
->setField(VID_POSTCODE
, m_postalAddress
->getPostCode());
1031 if (m_moduleData
!= NULL
)
1033 pMsg
->setField(VID_MODULE_DATA_COUNT
, (UINT16
)m_moduleData
->size());
1034 SendModuleDataCallbackData data
;
1036 data
.id
= VID_MODULE_DATA_BASE
;
1037 m_moduleData
->forEach(SendModuleDataCallback
, &data
);
1041 pMsg
->setField(VID_MODULE_DATA_COUNT
, (UINT16
)0);
1046 * Fill NXCP message with object's data - stage 2
1047 * Object's properties are not locked when this method is called. Should be
1048 * used only to fill data where properties lock is not enough (like data
1049 * collection configuration).
1051 void NetObj::fillMessageInternalStage2(NXCPMessage
*pMsg
)
1056 * Fill NXCP message with object's data
1058 void NetObj::fillMessage(NXCPMessage
*msg
)
1061 fillMessageInternal(msg
);
1063 fillMessageInternalStage2(msg
);
1066 m_accessList
->fillMessage(msg
);
1072 lockParentList(false);
1073 msg
->setField(VID_PARENT_CNT
, m_parentList
->size());
1074 for(i
= 0, dwId
= VID_PARENT_ID_BASE
; i
< m_parentList
->size(); i
++, dwId
++)
1075 msg
->setField(dwId
, m_parentList
->get(i
)->getId());
1078 lockChildList(false);
1079 msg
->setField(VID_CHILD_CNT
, m_childList
->size());
1080 for(i
= 0, dwId
= VID_CHILD_ID_BASE
; i
< m_childList
->size(); i
++, dwId
++)
1081 msg
->setField(dwId
, m_childList
->get(i
)->getId());
1086 * Handler for EnumerateSessions()
1088 static void BroadcastObjectChange(ClientSession
*pSession
, void *pArg
)
1090 if (pSession
->isAuthenticated())
1091 pSession
->onObjectChange((NetObj
*)pArg
);
1095 * Mark object as modified and put on client's notification queue
1096 * We assume that object is locked at the time of function call
1098 void NetObj::setModified(bool notify
)
1100 if (g_bModificationsLocked
)
1103 m_isModified
= true;
1104 m_dwTimeStamp
= (UINT32
)time(NULL
);
1106 // Send event to all connected clients
1107 if (notify
&& !m_isHidden
&& !m_isSystem
)
1108 EnumerateClientSessions(BroadcastObjectChange
, this);
1112 * Modify object from NXCP message - common wrapper
1114 UINT32
NetObj::modifyFromMessage(NXCPMessage
*msg
)
1117 UINT32 rcc
= modifyFromMessageInternal(msg
);
1124 * Modify object from NXCP message
1126 UINT32
NetObj::modifyFromMessageInternal(NXCPMessage
*pRequest
)
1128 // Change object's name
1129 if (pRequest
->isFieldExist(VID_OBJECT_NAME
))
1130 pRequest
->getFieldAsString(VID_OBJECT_NAME
, m_name
, MAX_OBJECT_NAME
);
1132 // Change object's status calculation/propagation algorithms
1133 if (pRequest
->isFieldExist(VID_STATUS_CALCULATION_ALG
))
1135 m_statusCalcAlg
= pRequest
->getFieldAsInt16(VID_STATUS_CALCULATION_ALG
);
1136 m_statusPropAlg
= pRequest
->getFieldAsInt16(VID_STATUS_PROPAGATION_ALG
);
1137 m_fixedStatus
= pRequest
->getFieldAsInt16(VID_FIXED_STATUS
);
1138 m_statusShift
= pRequest
->getFieldAsInt16(VID_STATUS_SHIFT
);
1139 m_statusTranslation
[0] = pRequest
->getFieldAsInt16(VID_STATUS_TRANSLATION_1
);
1140 m_statusTranslation
[1] = pRequest
->getFieldAsInt16(VID_STATUS_TRANSLATION_2
);
1141 m_statusTranslation
[2] = pRequest
->getFieldAsInt16(VID_STATUS_TRANSLATION_3
);
1142 m_statusTranslation
[3] = pRequest
->getFieldAsInt16(VID_STATUS_TRANSLATION_4
);
1143 m_statusSingleThreshold
= pRequest
->getFieldAsInt16(VID_STATUS_SINGLE_THRESHOLD
);
1144 m_statusThresholds
[0] = pRequest
->getFieldAsInt16(VID_STATUS_THRESHOLD_1
);
1145 m_statusThresholds
[1] = pRequest
->getFieldAsInt16(VID_STATUS_THRESHOLD_2
);
1146 m_statusThresholds
[2] = pRequest
->getFieldAsInt16(VID_STATUS_THRESHOLD_3
);
1147 m_statusThresholds
[3] = pRequest
->getFieldAsInt16(VID_STATUS_THRESHOLD_4
);
1151 if (pRequest
->isFieldExist(VID_IMAGE
))
1152 m_image
= pRequest
->getFieldAsGUID(VID_IMAGE
);
1154 // Change object's ACL
1155 if (pRequest
->isFieldExist(VID_ACL_SIZE
))
1158 m_inheritAccessRights
= pRequest
->getFieldAsBoolean(VID_INHERIT_RIGHTS
);
1159 m_accessList
->deleteAll();
1160 int count
= pRequest
->getFieldAsUInt32(VID_ACL_SIZE
);
1161 for(int i
= 0; i
< count
; i
++)
1162 m_accessList
->addElement(pRequest
->getFieldAsUInt32(VID_ACL_USER_BASE
+ i
),
1163 pRequest
->getFieldAsUInt32(VID_ACL_RIGHTS_BASE
+ i
));
1167 // Change trusted nodes list
1168 if (pRequest
->isFieldExist(VID_NUM_TRUSTED_NODES
))
1170 m_dwNumTrustedNodes
= pRequest
->getFieldAsUInt32(VID_NUM_TRUSTED_NODES
);
1171 m_pdwTrustedNodes
= (UINT32
*)realloc(m_pdwTrustedNodes
, sizeof(UINT32
) * m_dwNumTrustedNodes
);
1172 pRequest
->getFieldAsInt32Array(VID_TRUSTED_NODES
, m_dwNumTrustedNodes
, m_pdwTrustedNodes
);
1175 // Change custom attributes
1176 if (pRequest
->isFieldExist(VID_NUM_CUSTOM_ATTRIBUTES
))
1178 UINT32 i
, dwId
, dwNumElements
;
1179 TCHAR
*name
, *value
;
1181 dwNumElements
= pRequest
->getFieldAsUInt32(VID_NUM_CUSTOM_ATTRIBUTES
);
1182 m_customAttributes
.clear();
1183 for(i
= 0, dwId
= VID_CUSTOM_ATTRIBUTES_BASE
; i
< dwNumElements
; i
++)
1185 name
= pRequest
->getFieldAsString(dwId
++);
1186 value
= pRequest
->getFieldAsString(dwId
++);
1187 if ((name
!= NULL
) && (value
!= NULL
))
1188 m_customAttributes
.setPreallocated(name
, value
);
1192 // Change geolocation
1193 if (pRequest
->isFieldExist(VID_GEOLOCATION_TYPE
))
1195 m_geoLocation
= GeoLocation(*pRequest
);
1196 addLocationToHistory();
1199 if (pRequest
->isFieldExist(VID_SUBMAP_ID
))
1201 m_submapId
= pRequest
->getFieldAsUInt32(VID_SUBMAP_ID
);
1204 if (pRequest
->isFieldExist(VID_COUNTRY
))
1207 pRequest
->getFieldAsString(VID_COUNTRY
, buffer
, 64);
1208 m_postalAddress
->setCountry(buffer
);
1211 if (pRequest
->isFieldExist(VID_CITY
))
1214 pRequest
->getFieldAsString(VID_CITY
, buffer
, 64);
1215 m_postalAddress
->setCity(buffer
);
1218 if (pRequest
->isFieldExist(VID_STREET_ADDRESS
))
1221 pRequest
->getFieldAsString(VID_STREET_ADDRESS
, buffer
, 256);
1222 m_postalAddress
->setStreetAddress(buffer
);
1225 if (pRequest
->isFieldExist(VID_POSTCODE
))
1228 pRequest
->getFieldAsString(VID_POSTCODE
, buffer
, 32);
1229 m_postalAddress
->setPostCode(buffer
);
1232 // Change dashboard list
1233 if (pRequest
->isFieldExist(VID_DASHBOARDS
))
1235 pRequest
->getFieldAsInt32Array(VID_DASHBOARDS
, m_dashboards
);
1244 void NetObj::postModify()
1246 calculateCompoundStatus(TRUE
);
1250 * Get rights to object for specific user
1252 * @param userId user object ID
1254 UINT32
NetObj::getUserRights(UINT32 userId
)
1258 // Admin always has all rights to any object
1262 // Non-admin users have no rights to system objects
1266 // Check if have direct right assignment
1268 bool hasDirectRights
= m_accessList
->getUserRights(userId
, &dwRights
);
1271 if (!hasDirectRights
)
1273 // We don't. If this object inherit rights from parents, get them
1274 if (m_inheritAccessRights
)
1277 lockParentList(false);
1278 for(int i
= 0; i
< m_parentList
->size(); i
++)
1279 dwRights
|= m_parentList
->get(i
)->getUserRights(userId
);
1288 * Check if given user has specific rights on this object
1290 * @param userId user object ID
1291 * @param requiredRights bit mask of requested right
1292 * @return true if user has all rights specified in requested rights bit mask
1294 BOOL
NetObj::checkAccessRights(UINT32 userId
, UINT32 requiredRights
)
1296 UINT32 effectiveRights
= getUserRights(userId
);
1297 return (effectiveRights
& requiredRights
) == requiredRights
;
1301 * Drop all user privileges on current object
1303 void NetObj::dropUserAccess(UINT32 dwUserId
)
1306 bool modified
= m_accessList
->deleteElement(dwUserId
);
1317 * Set object's management status
1319 void NetObj::setMgmtStatus(BOOL bIsManaged
)
1325 if ((bIsManaged
&& (m_status
!= STATUS_UNMANAGED
)) ||
1326 ((!bIsManaged
) && (m_status
== STATUS_UNMANAGED
)))
1329 return; // Status is already correct
1332 oldStatus
= m_status
;
1333 m_status
= (bIsManaged
? STATUS_UNKNOWN
: STATUS_UNMANAGED
);
1335 // Generate event if current object is a node
1336 if (getObjectClass() == OBJECT_NODE
)
1337 PostEvent(bIsManaged
? EVENT_NODE_UNKNOWN
: EVENT_NODE_UNMANAGED
, m_id
, "d", oldStatus
);
1342 // Change status for child objects also
1343 lockChildList(false);
1344 for(int i
= 0; i
< m_childList
->size(); i
++)
1345 m_childList
->get(i
)->setMgmtStatus(bIsManaged
);
1348 // Cause parent object(s) to recalculate it's status
1349 lockParentList(false);
1350 for(int i
= 0; i
< m_parentList
->size(); i
++)
1351 m_parentList
->get(i
)->calculateCompoundStatus();
1356 * Check if given object is an our child (possibly indirect, i.e child of child)
1358 * @param id object ID to test
1360 bool NetObj::isChild(UINT32 id
)
1362 bool bResult
= false;
1364 // Check for our own ID (object ID should never change, so we may not lock object's data)
1368 // First, walk through our own child list
1371 lockChildList(false);
1372 for(int i
= 0; i
< m_childList
->size(); i
++)
1373 if (m_childList
->get(i
)->getId() == id
)
1381 // If given object is not in child list, check if it is indirect child
1384 lockChildList(false);
1385 for(int i
= 0; i
< m_childList
->size(); i
++)
1386 if (m_childList
->get(i
)->isChild(id
))
1398 * Send message to client, who requests poll, if any
1399 * This method is used by Node and Interface class objects
1401 void NetObj::sendPollerMsg(UINT32 dwRqId
, const TCHAR
*pszFormat
, ...)
1403 if (m_pollRequestor
!= NULL
)
1406 TCHAR szBuffer
[1024];
1408 va_start(args
, pszFormat
);
1409 _vsntprintf(szBuffer
, 1024, pszFormat
, args
);
1411 m_pollRequestor
->sendPollerMsg(dwRqId
, szBuffer
);
1416 * Add child node objects (direct and indirect childs) to list
1418 void NetObj::addChildNodesToList(ObjectArray
<Node
> *nodeList
, UINT32 dwUserId
)
1420 lockChildList(false);
1422 // Walk through our own child list
1423 for(int i
= 0; i
< m_childList
->size(); i
++)
1425 NetObj
*object
= m_childList
->get(i
);
1426 if (object
->getObjectClass() == OBJECT_NODE
)
1428 // Check if this node already in the list
1430 for(j
= 0; j
< nodeList
->size(); j
++)
1431 if (nodeList
->get(j
)->getId() == object
->getId())
1433 if (j
== nodeList
->size())
1435 object
->incRefCount();
1436 nodeList
->add((Node
*)object
);
1441 if (object
->checkAccessRights(dwUserId
, OBJECT_ACCESS_READ
))
1442 object
->addChildNodesToList(nodeList
, dwUserId
);
1450 * Add child data collection targets (direct and indirect childs) to list
1452 void NetObj::addChildDCTargetsToList(ObjectArray
<DataCollectionTarget
> *dctList
, UINT32 dwUserId
)
1454 lockChildList(false);
1456 // Walk through our own child list
1457 for(int i
= 0; i
< m_childList
->size(); i
++)
1459 NetObj
*object
= m_childList
->get(i
);
1460 if (!object
->checkAccessRights(dwUserId
, OBJECT_ACCESS_READ
))
1463 if (object
->isDataCollectionTarget())
1465 // Check if this objects already in the list
1467 for(j
= 0; j
< dctList
->size(); j
++)
1468 if (dctList
->get(j
)->getId() == object
->getId())
1470 if (j
== dctList
->size())
1472 object
->incRefCount();
1473 dctList
->add((DataCollectionTarget
*)object
);
1476 object
->addChildDCTargetsToList(dctList
, dwUserId
);
1483 * Hide object and all its childs
1487 lockChildList(false);
1488 for(int i
= 0; i
< m_childList
->size(); i
++)
1489 m_childList
->get(i
)->hide();
1498 * Unhide object and all its childs
1500 void NetObj::unhide()
1505 EnumerateClientSessions(BroadcastObjectChange
, this);
1508 lockChildList(false);
1509 for(int i
= 0; i
< m_childList
->size(); i
++)
1510 m_childList
->get(i
)->unhide();
1515 * Return status propagated to parent
1517 int NetObj::getPropagatedStatus()
1521 if (m_statusPropAlg
== SA_PROPAGATE_DEFAULT
)
1523 iStatus
= DefaultPropagatedStatus(m_status
);
1527 switch(m_statusPropAlg
)
1529 case SA_PROPAGATE_UNCHANGED
:
1532 case SA_PROPAGATE_FIXED
:
1533 iStatus
= ((m_status
> STATUS_NORMAL
) && (m_status
< STATUS_UNKNOWN
)) ? m_fixedStatus
: m_status
;
1535 case SA_PROPAGATE_RELATIVE
:
1536 if ((m_status
> STATUS_NORMAL
) && (m_status
< STATUS_UNKNOWN
))
1538 iStatus
= m_status
+ m_statusShift
;
1541 if (iStatus
> STATUS_CRITICAL
)
1542 iStatus
= STATUS_CRITICAL
;
1549 case SA_PROPAGATE_TRANSLATED
:
1550 if ((m_status
> STATUS_NORMAL
) && (m_status
< STATUS_UNKNOWN
))
1552 iStatus
= m_statusTranslation
[m_status
- 1];
1560 iStatus
= STATUS_UNKNOWN
;
1568 * Prepare object for deletion. Method should return only
1569 * when object deletion is safe
1571 void NetObj::prepareForDeletion()
1576 * Set object's comments.
1577 * NOTE: pszText should be dynamically allocated or NULL
1579 void NetObj::setComments(TCHAR
*text
)
1589 * Copy object's comments to NXCP message
1591 void NetObj::commentsToMessage(NXCPMessage
*pMsg
)
1594 pMsg
->setField(VID_COMMENTS
, CHECK_NULL_EX(m_comments
));
1599 * Load trusted nodes list from database
1601 bool NetObj::loadTrustedNodes(DB_HANDLE hdb
)
1607 _sntprintf(query
, 256, _T("SELECT target_node_id FROM trusted_nodes WHERE source_object_id=%d"), m_id
);
1608 hResult
= DBSelect(hdb
, query
);
1609 if (hResult
!= NULL
)
1611 count
= DBGetNumRows(hResult
);
1614 m_dwNumTrustedNodes
= count
;
1615 m_pdwTrustedNodes
= (UINT32
*)malloc(sizeof(UINT32
) * count
);
1616 for(i
= 0; i
< count
; i
++)
1618 m_pdwTrustedNodes
[i
] = DBGetFieldULong(hResult
, i
, 0);
1621 DBFreeResult(hResult
);
1623 return (hResult
!= NULL
);
1627 * Save list of trusted nodes to database
1629 bool NetObj::saveTrustedNodes(DB_HANDLE hdb
)
1635 _sntprintf(query
, 256, _T("DELETE FROM trusted_nodes WHERE source_object_id=%d"), m_id
);
1636 if (DBQuery(hdb
, query
))
1638 for(i
= 0; i
< m_dwNumTrustedNodes
; i
++)
1640 _sntprintf(query
, 256, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"),
1641 m_id
, m_pdwTrustedNodes
[i
]);
1642 if (!DBQuery(hdb
, query
))
1645 if (i
== m_dwNumTrustedNodes
)
1652 * Check if given node is in trust list
1653 * Will always return TRUE if system parameter CheckTrustedNodes set to 0
1655 bool NetObj::isTrustedNode(UINT32 id
)
1659 if (g_flags
& AF_CHECK_TRUSTED_NODES
)
1664 for(i
= 0, rc
= false; i
< m_dwNumTrustedNodes
; i
++)
1666 if (m_pdwTrustedNodes
[i
] == id
)
1682 * Get list of parent objects for NXSL script
1684 NXSL_Array
*NetObj::getParentsForNXSL()
1686 NXSL_Array
*parents
= new NXSL_Array
;
1689 lockParentList(false);
1690 for(int i
= 0; i
< m_parentList
->size(); i
++)
1692 NetObj
*obj
= m_parentList
->get(i
);
1693 if ((obj
->getObjectClass() == OBJECT_CONTAINER
) ||
1694 (obj
->getObjectClass() == OBJECT_SERVICEROOT
) ||
1695 (obj
->getObjectClass() == OBJECT_NETWORK
))
1697 parents
->set(index
++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass
, obj
)));
1706 * Get list of child objects for NXSL script
1708 NXSL_Array
*NetObj::getChildrenForNXSL()
1710 NXSL_Array
*children
= new NXSL_Array
;
1713 lockChildList(false);
1714 for(int i
= 0; i
< m_childList
->size(); i
++)
1716 NetObj
*obj
= m_childList
->get(i
);
1717 if (obj
->getObjectClass() == OBJECT_NODE
)
1719 children
->set(index
++, new NXSL_Value(new NXSL_Object(&g_nxslNodeClass
, obj
)));
1721 else if (obj
->getObjectClass() == OBJECT_INTERFACE
)
1723 children
->set(index
++, new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass
, obj
)));
1727 children
->set(index
++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass
, obj
)));
1736 * Get full list of child objects (including both direct and indirect childs)
1738 void NetObj::getFullChildListInternal(ObjectIndex
*list
, bool eventSourceOnly
)
1740 lockChildList(false);
1741 for(int i
= 0; i
< m_childList
->size(); i
++)
1743 NetObj
*obj
= m_childList
->get(i
);
1744 if (!eventSourceOnly
|| IsEventSource(obj
->getObjectClass()))
1745 list
->put(obj
->getId(), obj
);
1746 obj
->getFullChildListInternal(list
, eventSourceOnly
);
1752 * Get full list of child objects (including both direct and indirect childs).
1753 * Returned array is dynamically allocated and must be deleted by the caller.
1755 * @param eventSourceOnly if true, only objects that can be event source will be included
1757 ObjectArray
<NetObj
> *NetObj::getFullChildList(bool eventSourceOnly
, bool updateRefCount
)
1760 getFullChildListInternal(&list
, eventSourceOnly
);
1761 return list
.getObjects(updateRefCount
);
1765 * Get list of child objects (direct only). Returned array is
1766 * dynamically allocated and must be deleted by the caller.
1768 * @param typeFilter Only return objects with class ID equals given value.
1769 * Set to -1 to disable filtering.
1771 ObjectArray
<NetObj
> *NetObj::getChildList(int typeFilter
)
1773 lockChildList(false);
1774 ObjectArray
<NetObj
> *list
= new ObjectArray
<NetObj
>((int)m_childList
->size(), 16, false);
1775 for(int i
= 0; i
< m_childList
->size(); i
++)
1777 if ((typeFilter
== -1) || (typeFilter
== m_childList
->get(i
)->getObjectClass()))
1778 list
->add(m_childList
->get(i
));
1785 * Get list of parent objects (direct only). Returned array is
1786 * dynamically allocated and must be deleted by the caller.
1788 * @param typeFilter Only return objects with class ID equals given value.
1789 * Set to -1 to disable filtering.
1791 ObjectArray
<NetObj
> *NetObj::getParentList(int typeFilter
)
1793 lockParentList(false);
1794 ObjectArray
<NetObj
> *list
= new ObjectArray
<NetObj
>(m_parentList
->size(), 16, false);
1795 for(int i
= 0; i
< m_parentList
->size(); i
++)
1797 if ((typeFilter
== -1) || (typeFilter
== m_parentList
->get(i
)->getObjectClass()))
1798 list
->add(m_parentList
->get(i
));
1805 * FInd child object by name (with optional class filter)
1807 NetObj
*NetObj::findChildObject(const TCHAR
*name
, int typeFilter
)
1809 NetObj
*object
= NULL
;
1810 lockChildList(false);
1811 for(int i
= 0; i
< m_childList
->size(); i
++)
1813 NetObj
*o
= m_childList
->get(i
);
1814 if (((typeFilter
== -1) || (typeFilter
== o
->getObjectClass())) && !_tcsicmp(name
, o
->getName()))
1825 * Called by client session handler to check if threshold summary should
1826 * be shown for this object. Default implementation always returns false.
1828 bool NetObj::showThresholdSummary()
1834 * Must return true if object is a possible event source
1836 bool NetObj::isEventSource()
1842 * Must return true if object is a possible data collection target
1844 bool NetObj::isDataCollectionTarget()
1852 ModuleData
*NetObj::getModuleData(const TCHAR
*module
)
1855 ModuleData
*data
= (m_moduleData
!= NULL
) ? m_moduleData
->get(module
) : NULL
;
1863 void NetObj::setModuleData(const TCHAR
*module
, ModuleData
*data
)
1866 if (m_moduleData
== NULL
)
1867 m_moduleData
= new StringObjectMap
<ModuleData
>(true);
1868 m_moduleData
->set(module
, data
);
1873 * Add new location entry
1875 void NetObj::addLocationToHistory()
1877 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
1878 UINT32 startTimestamp
;
1881 if (!isLocationTableExists())
1883 DbgPrintf(4, _T("NetObj::addLocationToHistory: Geolocation history table will be created for object %s [%d]"), m_name
, m_id
);
1884 if (!createLocationHistoryTable(hdb
))
1886 DbgPrintf(4, _T("NetObj::addLocationToHistory: Error creating geolocation history table for object %s [%d]"), m_name
, m_id
);
1893 case DB_SYNTAX_ORACLE
:
1894 query
= _T("SELECT * FROM (SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC) WHERE ROWNUM<=1");
1896 case DB_SYNTAX_MSSQL
:
1897 query
= _T("SELECT TOP 1 latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC");
1900 query
= _T("SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC FETCH FIRST 200 ROWS ONLY");
1903 query
= _T("SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC LIMIT 1");
1906 TCHAR preparedQuery
[256];
1907 _sntprintf(preparedQuery
, 256, query
, m_id
);
1908 DB_STATEMENT hStmt
= DBPrepare(hdb
, preparedQuery
);
1913 hResult
= DBSelectPrepared(hStmt
);
1914 if (hResult
== NULL
)
1916 if (DBGetNumRows(hResult
) > 0)
1918 startTimestamp
= DBGetFieldULong(hResult
, 0, 3);
1919 isSamePlace
= m_geoLocation
.sameLocation(DBGetFieldDouble(hResult
, 0, 0), DBGetFieldDouble(hResult
, 0, 1), DBGetFieldLong(hResult
, 0, 2));
1920 DBFreeStatement(hStmt
);
1921 DBFreeResult(hResult
);
1925 isSamePlace
= false;
1931 _sntprintf(query
, 255, _T("UPDATE gps_history_%d SET end_timestamp = ? WHERE start_timestamp =? "), m_id
);
1932 hStmt
= DBPrepare(hdb
, query
);
1933 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, (UINT32
)m_geoLocation
.getTimestamp());
1934 DBBind(hStmt
, 2, DB_SQLTYPE_INTEGER
, startTimestamp
);
1939 _sntprintf(query
, 255, _T("INSERT INTO gps_history_%d (latitude,longitude,")
1940 _T("accuracy,start_timestamp,end_timestamp) VALUES (?,?,?,?,?)"), m_id
);
1941 hStmt
= DBPrepare(hdb
, query
);
1943 TCHAR lat
[32], lon
[32];
1944 _sntprintf(lat
, 32, _T("%f"), m_geoLocation
.getLatitude());
1945 _sntprintf(lon
, 32, _T("%f"), m_geoLocation
.getLongitude());
1947 DBBind(hStmt
, 1, DB_SQLTYPE_VARCHAR
, lat
, DB_BIND_STATIC
);
1948 DBBind(hStmt
, 2, DB_SQLTYPE_VARCHAR
, lon
, DB_BIND_STATIC
);
1949 DBBind(hStmt
, 3, DB_SQLTYPE_INTEGER
, (LONG
)m_geoLocation
.getAccuracy());
1950 DBBind(hStmt
, 4, DB_SQLTYPE_INTEGER
, (UINT32
)m_geoLocation
.getTimestamp());
1951 DBBind(hStmt
, 5, DB_SQLTYPE_INTEGER
, (UINT32
)m_geoLocation
.getTimestamp());
1958 DBFreeStatement(hStmt
);
1959 DBConnectionPoolReleaseConnection(hdb
);
1963 DBFreeStatement(hStmt
);
1964 DbgPrintf(4, _T("NetObj::addLocationToHistory(%s [%d]): Failed to add location to history"), m_name
, m_id
);
1965 DBConnectionPoolReleaseConnection(hdb
);
1970 * Check if given data table exist
1972 bool NetObj::isLocationTableExists()
1975 _sntprintf(table
, 256, _T("gps_history_%d"), m_id
);
1976 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
1977 int rc
= DBIsTableExist(hdb
, table
);
1978 if (rc
== DBIsTableExist_Failure
)
1980 _tprintf(_T("WARNING: call to DBIsTableExist(\"%s\") failed\n"), table
);
1982 DBConnectionPoolReleaseConnection(hdb
);
1983 return rc
!= DBIsTableExist_NotFound
;
1987 * Create table for storing geolocation history for this object
1989 bool NetObj::createLocationHistoryTable(DB_HANDLE hdb
)
1991 TCHAR szQuery
[256], szQueryTemplate
[256];
1992 MetaDataReadStr(_T("LocationHistory"), szQueryTemplate
, 255, _T(""));
1993 _sntprintf(szQuery
, 256, szQueryTemplate
, m_id
);
1994 if (!DBQuery(hdb
, szQuery
))
2001 * Set status calculation method
2003 void NetObj::setStatusCalculation(int method
, int arg1
, int arg2
, int arg3
, int arg4
)
2006 m_statusCalcAlg
= method
;
2009 case SA_CALCULATE_SINGLE_THRESHOLD
:
2010 m_statusSingleThreshold
= arg1
;
2012 case SA_CALCULATE_MULTIPLE_THRESHOLDS
:
2013 m_statusThresholds
[0] = arg1
;
2014 m_statusThresholds
[1] = arg2
;
2015 m_statusThresholds
[2] = arg3
;
2016 m_statusThresholds
[3] = arg4
;
2026 * Set status propagation method
2028 void NetObj::setStatusPropagation(int method
, int arg1
, int arg2
, int arg3
, int arg4
)
2031 m_statusPropAlg
= method
;
2034 case SA_PROPAGATE_FIXED
:
2035 m_fixedStatus
= arg1
;
2037 case SA_PROPAGATE_RELATIVE
:
2038 m_statusShift
= arg1
;
2040 case SA_PROPAGATE_TRANSLATED
:
2041 m_statusTranslation
[0] = arg1
;
2042 m_statusTranslation
[1] = arg2
;
2043 m_statusTranslation
[2] = arg3
;
2044 m_statusTranslation
[3] = arg4
;
2054 * Enter maintenance mode
2056 void NetObj::enterMaintenanceMode()
2058 DbgPrintf(4, _T("Entering maintenance mode for object %s [%d] (%s)"), m_name
, m_id
, getObjectClassName());
2060 lockChildList(false);
2061 for(int i
= 0; i
< m_childList
->size(); i
++)
2063 NetObj
*object
= m_childList
->get(i
);
2064 if (object
->getStatus() != STATUS_UNMANAGED
)
2065 object
->enterMaintenanceMode();
2071 * Leave maintenance mode
2073 void NetObj::leaveMaintenanceMode()
2075 DbgPrintf(4, _T("Leaving maintenance mode for object %s [%d] (%s)"), m_name
, m_id
, getObjectClassName());
2077 lockChildList(false);
2078 for(int i
= 0; i
< m_childList
->size(); i
++)
2080 NetObj
*object
= m_childList
->get(i
);
2081 if (object
->getStatus() != STATUS_UNMANAGED
)
2082 object
->leaveMaintenanceMode();
2088 * Get all custom attributes as NXSL hash map
2090 NXSL_Value
*NetObj::getCustomAttributesForNXSL() const
2092 NXSL_HashMap
*map
= new NXSL_HashMap();
2094 StructArray
<KeyValuePair
> *attributes
= m_customAttributes
.toArray();
2095 for(int i
= 0; i
< attributes
->size(); i
++)
2097 KeyValuePair
*p
= attributes
->get(i
);
2098 map
->set(p
->key
, new NXSL_Value((const TCHAR
*)p
->value
));
2102 return new NXSL_Value(map
);
2106 * Create NXSL object for this object
2108 NXSL_Value
*NetObj::createNXSLObject()
2110 return new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass
, this));