2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 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.
26 * Redefined status calculation for template group
28 void TemplateGroup
::calculateCompoundStatus(BOOL bForcedRecalc
)
30 m_status
= STATUS_NORMAL
;
34 * Called by client session handler to check if threshold summary should be shown for this object.
36 bool TemplateGroup
::showThresholdSummary()
42 * Template object constructor
44 Template
::Template() : NetObj()
46 m_dcObjects
= new ObjectArray
<DCObject
>(8, 16, true);
49 m_dwVersion
= 0x00010000; // Initial version is 1.0
51 m_applyFilterSource
= NULL
;
52 m_status
= STATUS_NORMAL
;
53 m_dciAccessLock
= RWLockCreate();
54 m_dciListModified
= false;
58 * Constructor for new template object
60 Template
::Template(const TCHAR
*pszName
) : NetObj()
62 nx_strncpy(m_name
, pszName
, MAX_OBJECT_NAME
);
63 m_dcObjects
= new ObjectArray
<DCObject
>(8, 16, true);
66 m_dwVersion
= 0x00010000; // Initial version is 1.0
68 m_applyFilterSource
= NULL
;
69 m_status
= STATUS_NORMAL
;
71 m_dciAccessLock
= RWLockCreate();
72 m_dciListModified
= false;
76 * Create template object from import file
78 Template
::Template(ConfigEntry
*config
) : NetObj()
82 m_status
= STATUS_NORMAL
;
83 m_dciAccessLock
= RWLockCreate();
84 m_dciListModified
= false;
87 uuid guid
= config
->getSubEntryValueAsUUID(_T("guid"));
92 nx_strncpy(m_name
, config
->getSubEntryValue(_T("name"), 0, _T("Unnamed Template")), MAX_OBJECT_NAME
);
93 m_dwVersion
= config
->getSubEntryValueAsUInt(_T("version"), 0, 0x00010000);
94 m_flags
= config
->getSubEntryValueAsUInt(_T("flags"), 0, 0);
98 m_applyFilterSource
= NULL
;
99 if (m_flags
& TF_AUTO_APPLY
)
100 setAutoApplyFilter(config
->getSubEntryValue(_T("filter")));
103 m_dcObjects
= new ObjectArray
<DCObject
>(8, 16, true);
104 ConfigEntry
*dcRoot
= config
->findEntry(_T("dataCollection"));
107 ObjectArray
<ConfigEntry
> *dcis
= dcRoot
->getSubEntries(_T("dci#*"));
108 for(int i
= 0; i
< dcis
->size(); i
++)
110 m_dcObjects
->add(new DCItem(dcis
->get(i
), this));
114 ObjectArray
<ConfigEntry
> *dctables
= dcRoot
->getSubEntries(_T("dctable#*"));
115 for(int i
= 0; i
< dctables
->size(); i
++)
117 m_dcObjects
->add(new DCTable(dctables
->get(i
), this));
126 Template
::~Template()
129 delete m_applyFilter
;
130 safe_free(m_applyFilterSource
);
131 RWLockDestroy(m_dciAccessLock
);
135 * Destroy all related data collection items.
137 void Template
::destroyItems()
139 m_dcObjects
->clear();
143 * Set auto apply filter.
145 * @param filter new filter script code or NULL to clear filter
147 void Template
::setAutoApplyFilter(const TCHAR
*filter
)
150 free(m_applyFilterSource
);
151 delete m_applyFilter
;
156 m_applyFilterSource
= _tcsdup(filter
);
157 m_applyFilter
= NXSLCompile(m_applyFilterSource
, error
, 256, NULL
);
158 if (m_applyFilter
== NULL
)
161 _sntprintf(buffer
, 1024, _T("Template::%s::%d"), m_name
, m_id
);
162 PostEvent(EVENT_SCRIPT_ERROR
, g_dwMgmtNode
, "ssd", buffer
, error
, m_id
);
163 nxlog_write(MSG_TEMPLATE_SCRIPT_COMPILATION_ERROR
, NXLOG_WARNING
, "dss", m_id
, m_name
, error
);
168 m_applyFilterSource
= NULL
;
169 m_applyFilter
= NULL
;
171 setModified(MODIFY_OTHER
);
176 * Create template object from database data
178 * @param dwId object ID
180 bool Template
::loadFromDatabase(DB_HANDLE hdb
, UINT32 dwId
)
183 UINT32 i
, dwNumNodes
, dwNodeId
;
188 if (!loadCommonProperties(hdb
))
191 _sntprintf(szQuery
, sizeof(szQuery
) / sizeof(TCHAR
), _T("SELECT version,apply_filter FROM templates WHERE id=%d"), dwId
);
192 DB_RESULT hResult
= DBSelect(hdb
, szQuery
);
196 if (DBGetNumRows(hResult
) == 0)
198 // No object with given ID in database
199 DBFreeResult(hResult
);
205 m_dwVersion
= DBGetFieldULong(hResult
, 0, 0);
206 m_applyFilterSource
= DBGetField(hResult
, 0, 1, NULL
, 0);
207 if (m_applyFilterSource
!= NULL
)
210 m_applyFilter
= NXSLCompile(m_applyFilterSource
, error
, 256, NULL
);
211 if (m_applyFilter
== NULL
)
214 _sntprintf(buffer
, 1024, _T("Template::%s::%d"), m_name
, m_id
);
215 PostEvent(EVENT_SCRIPT_ERROR
, g_dwMgmtNode
, "ssd", buffer
, error
, m_id
);
216 nxlog_write(MSG_TEMPLATE_SCRIPT_COMPILATION_ERROR
, EVENTLOG_WARNING_TYPE
, "dss", m_id
, m_name
, error
);
219 DBFreeResult(hResult
);
221 // Load DCI and access list
223 loadItemsFromDB(hdb
);
224 for(i
= 0; i
< (UINT32
)m_dcObjects
->size(); i
++)
225 if (!m_dcObjects
->get(i
)->loadThresholdsFromDB(hdb
))
228 // Load related nodes list
231 _sntprintf(szQuery
, sizeof(szQuery
) / sizeof(TCHAR
), _T("SELECT node_id FROM dct_node_map WHERE template_id=%d"), m_id
);
232 hResult
= DBSelect(hdb
, szQuery
);
235 dwNumNodes
= DBGetNumRows(hResult
);
236 for(i
= 0; i
< dwNumNodes
; i
++)
238 dwNodeId
= DBGetFieldULong(hResult
, i
, 0);
239 pObject
= FindObjectById(dwNodeId
);
242 if ((pObject
->getObjectClass() == OBJECT_NODE
) || (pObject
->getObjectClass() == OBJECT_CLUSTER
) || (pObject
->getObjectClass() == OBJECT_MOBILEDEVICE
) || (pObject
->getObjectClass() == OBJECT_SENSOR
))
245 pObject
->addParent(this);
249 nxlog_write(MSG_DCT_MAP_NOT_NODE
, EVENTLOG_ERROR_TYPE
, "dd", m_id
, dwNodeId
);
254 nxlog_write(MSG_INVALID_DCT_MAP
, EVENTLOG_ERROR_TYPE
, "dd", m_id
, dwNodeId
);
257 DBFreeResult(hResult
);
261 m_status
= STATUS_NORMAL
;
267 * Save object to database
269 bool Template
::saveToDatabase(DB_HANDLE hdb
)
273 bool success
= saveCommonProperties(hdb
);
275 if (success
&& (m_modified
& MODIFY_OTHER
))
278 if (IsDatabaseRecordExist(hdb
, _T("templates"), _T("id"), m_id
))
280 hStmt
= DBPrepare(hdb
, _T("UPDATE templates SET version=?,apply_filter=? WHERE id=?"));
284 hStmt
= DBPrepare(hdb
, _T("INSERT INTO templates (version,apply_filter,id) VALUES (?,?,?)"));
288 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_dwVersion
);
289 DBBind(hStmt
, 2, DB_SQLTYPE_TEXT
, m_applyFilterSource
, DB_BIND_STATIC
);
290 DBBind(hStmt
, 3, DB_SQLTYPE_INTEGER
, m_id
);
291 success
= DBExecute(hStmt
);
292 DBFreeStatement(hStmt
);
302 success
= saveACLToDB(hdb
);
306 if (success
&& (m_modified
& MODIFY_RELATIONS
))
308 // Update members list
309 success
= executeQueryOnObject(hdb
, _T("DELETE FROM dct_node_map WHERE template_id=?"));
310 lockChildList(false);
311 if (success
&& !m_childList
->isEmpty())
313 DB_STATEMENT hStmt
= DBPrepare(hdb
, _T("INSERT INTO dct_node_map (template_id,node_id) VALUES (?,?)"));
316 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
317 for(int i
= 0; success
&& (i
< m_childList
->size()); i
++)
319 DBBind(hStmt
, 2, DB_SQLTYPE_INTEGER
, m_childList
->get(i
)->getId());
320 success
= DBExecute(hStmt
);
322 DBFreeStatement(hStmt
);
332 // Save data collection items
333 if (success
&& (m_modified
& MODIFY_DATA_COLLECTION
))
335 lockDciAccess(false);
336 for(int i
= 0; success
&& (i
< m_dcObjects
->size()); i
++)
337 success
= m_dcObjects
->get(i
)->saveToDatabase(hdb
);
341 // Clear modifications flag
350 * Delete object from database
352 bool Template
::deleteFromDatabase(DB_HANDLE hdb
)
354 bool success
= NetObj
::deleteFromDatabase(hdb
);
357 if (getObjectClass() == OBJECT_TEMPLATE
)
359 success
= executeQueryOnObject(hdb
, _T("DELETE FROM templates WHERE id=?"));
361 success
= executeQueryOnObject(hdb
, _T("DELETE FROM dct_node_map WHERE template_id=?"));
365 success
= executeQueryOnObject(hdb
, _T("DELETE FROM dct_node_map WHERE node_id=?"));
368 success
= executeQueryOnObject(hdb
, _T("DELETE FROM items WHERE node_id=?"));
370 success
= executeQueryOnObject(hdb
, _T("UPDATE items SET template_id=0 WHERE template_id=?"));
376 * Load data collection items from database
378 void Template
::loadItemsFromDB(DB_HANDLE hdb
)
380 DB_STATEMENT hStmt
= DBPrepare(hdb
,
381 _T("SELECT item_id,name,source,datatype,polling_interval,retention_time,")
382 _T("status,delta_calculation,transformation,template_id,description,")
383 _T("instance,template_item_id,flags,resource_id,")
384 _T("proxy_node,base_units,unit_multiplier,custom_units_name,")
385 _T("perftab_settings,system_tag,snmp_port,snmp_raw_value_type,")
386 _T("instd_method,instd_data,instd_filter,samples,comments,guid,npe_name ")
387 _T("FROM items WHERE node_id=?"));
390 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
391 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
394 int count
= DBGetNumRows(hResult
);
395 for(int i
= 0; i
< count
; i
++)
396 m_dcObjects
->add(new DCItem(hdb
, hResult
, i
, this));
397 DBFreeResult(hResult
);
399 DBFreeStatement(hStmt
);
402 hStmt
= DBPrepare(hdb
,
403 _T("SELECT item_id,template_id,template_item_id,name,")
404 _T("description,flags,source,snmp_port,polling_interval,retention_time,")
405 _T("status,system_tag,resource_id,proxy_node,perftab_settings,")
406 _T("transformation_script,comments,guid,instd_method,instd_data,instd_filter,instance FROM dc_tables WHERE node_id=?"));
409 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, m_id
);
410 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
413 int count
= DBGetNumRows(hResult
);
414 for(int i
= 0; i
< count
; i
++)
415 m_dcObjects
->add(new DCTable(hdb
, hResult
, i
, this));
416 DBFreeResult(hResult
);
418 DBFreeStatement(hStmt
);
423 * Add data collection object to node
425 bool Template
::addDCObject(DCObject
*object
, bool alreadyLocked
)
428 bool success
= false;
430 lockDciAccess(true); // write lock
431 // Check if that object exists
432 for(i
= 0; i
< m_dcObjects
->size(); i
++)
433 if (m_dcObjects
->get(i
)->getId() == object
->getId())
434 break; // Object with specified id already exist
436 if (i
== m_dcObjects
->size()) // Add new item
438 m_dcObjects
->add(object
);
439 object
->setLastPollTime(0); // Cause item to be polled immediately
440 if (object
->getStatus() != ITEM_STATUS_DISABLED
)
441 object
->setStatus(ITEM_STATUS_ACTIVE
, false);
442 object
->clearBusyFlag();
452 setModified(MODIFY_DATA_COLLECTION
);
459 * Delete data collection object from node
461 bool Template
::deleteDCObject(UINT32 dcObjectId
, bool needLock
)
463 bool success
= false;
466 lockDciAccess(true); // write lock
468 // Check if that item exists
469 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
471 DCObject
*object
= m_dcObjects
->get(i
);
472 if (object
->getId() == dcObjectId
)
474 // Check if it is instance DCI
475 if ((object
->getType() == DCO_TYPE_ITEM
) && (((DCItem
*)object
)->getInstanceDiscoveryMethod() != IDM_NONE
))
477 deleteChildDCIs(dcObjectId
);
479 // Index may be incorrect at this point
480 if (m_dcObjects
->get(i
) != object
)
481 i
= m_dcObjects
->indexOf(object
);
484 DbgPrintf(7, _T("Template::DeleteDCObject: deleting DCObject %d from object %d"), (int)dcObjectId
, (int)m_id
);
485 destroyItem(object
, i
);
487 DbgPrintf(7, _T("Template::DeleteDCObject: DCO deleted from object %d"), (int)m_id
);
498 setModified(MODIFY_DATA_COLLECTION
, false);
505 * Deletes child DCI objects of instance discovery DCI.
506 * It is assumed that list is already locked
508 void Template
::deleteChildDCIs(UINT32 dcObjectId
)
510 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
512 DCObject
*subObject
= m_dcObjects
->get(i
);
513 if (subObject
->getTemplateItemId() == dcObjectId
)
515 nxlog_debug(7, _T("Template::DeleteDCObject: deleting DCObject %d created by DCObject %d instance discovery from object %d"), (int)subObject
->getId(), (int)dcObjectId
, (int)m_id
);
516 destroyItem(subObject
, i
);
524 * Deletes or schedules deletion from DB and removes it from index
525 * It is assumed that list is already locked
527 void Template
::destroyItem(DCObject
*object
, int index
)
529 if (object
->prepareForDeletion())
531 // Physically delete DCI only if it is not busy
532 // Busy DCIs will be deleted by data collector
533 object
->deleteFromDatabase();
534 m_dcObjects
->remove(index
);
538 m_dcObjects
->unlink(index
);
539 DbgPrintf(7, _T("Template::DeleteItem: destruction of DCO %d delayed"), (int)object
->getId());
544 * Modify data collection object from NXCP message
546 bool Template
::updateDCObject(UINT32 dwItemId
, NXCPMessage
*pMsg
, UINT32
*pdwNumMaps
, UINT32
**ppdwMapIndex
, UINT32
**ppdwMapId
)
548 bool success
= false;
550 lockDciAccess(false);
552 // Check if that item exists
553 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
555 DCObject
*object
= m_dcObjects
->get(i
);
556 if (object
->getId() == dwItemId
)
558 if (object
->getType() == DCO_TYPE_ITEM
)
560 ((DCItem
*)object
)->updateFromMessage(pMsg
, pdwNumMaps
, ppdwMapIndex
, ppdwMapId
);
561 if (((DCItem
*)object
)->getInstanceDiscoveryMethod() != IDM_NONE
)
563 updateInstanceDiscoveryItems((DCItem
*)object
);
568 object
->updateFromMessage(pMsg
);
580 setModified(MODIFY_DATA_COLLECTION
);
588 * Update DCIs created by instance dicovery.
589 * This method expects DCI access already locked.
591 * @param dci instance discovery template DCI
593 void Template
::updateInstanceDiscoveryItems(DCItem
*dci
)
595 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
597 DCObject
*object
= m_dcObjects
->get(i
);
598 if ((object
->getType() == DCO_TYPE_ITEM
) && (object
->getTemplateId() == m_id
) && (object
->getTemplateItemId() == dci
->getId()))
600 object
->updateFromTemplate(dci
);
606 * Set status for group of DCIs
608 bool Template
::setItemStatus(UINT32 dwNumItems
, UINT32
*pdwItemList
, int iStatus
)
612 lockDciAccess(false);
613 for(UINT32 i
= 0; i
< dwNumItems
; i
++)
616 for(j
= 0; j
< m_dcObjects
->size(); j
++)
618 if (m_dcObjects
->get(j
)->getId() == pdwItemList
[i
])
620 m_dcObjects
->get(j
)->setStatus(iStatus
, true);
624 if (j
== m_dcObjects
->size())
625 success
= false; // Invalid DCI ID provided
632 * Lock data collection items list
634 bool Template
::lockDCIList(int sessionId
, const TCHAR
*pszNewOwner
, TCHAR
*pszCurrOwner
)
639 if (m_dciLockStatus
== -1)
641 m_dciLockStatus
= sessionId
;
642 m_dciListModified
= false;
643 nx_strncpy(m_szCurrDCIOwner
, pszNewOwner
, MAX_SESSION_NAME
);
648 if (pszCurrOwner
!= NULL
)
649 _tcscpy(pszCurrOwner
, m_szCurrDCIOwner
);
657 * Unlock data collection items list
659 bool Template
::unlockDCIList(int sessionId
)
661 bool success
= false;
662 bool callChangeHook
= false;
665 if (m_dciLockStatus
== sessionId
)
667 m_dciLockStatus
= -1;
668 if (m_dciListModified
)
670 if (getObjectClass() == OBJECT_TEMPLATE
)
672 setModified(MODIFY_OTHER
| MODIFY_DATA_COLLECTION
);
673 callChangeHook
= true;
675 m_dciListModified
= false;
681 onDataCollectionChange();
687 * Send DCI list to client
689 void Template
::sendItemsToClient(ClientSession
*pSession
, UINT32 dwRqId
)
695 msg
.setCode(CMD_NODE_DCI
);
697 lockDciAccess(false);
699 // Walk through items list
700 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
702 m_dcObjects
->get(i
)->createMessage(&msg
);
703 pSession
->sendMessage(&msg
);
704 msg
.deleteAllFields();
709 // Send end-of-list indicator
710 msg
.setEndOfSequence();
711 pSession
->sendMessage(&msg
);
715 * Get DCI's data type
717 int Template
::getItemType(UINT32 dwItemId
)
721 lockDciAccess(false);
722 // Check if that item exists
723 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
725 DCObject
*object
= m_dcObjects
->get(i
);
726 if (object
->getId() == dwItemId
)
728 if (object
->getType() == DCO_TYPE_ITEM
)
730 iType
= ((DCItem
*)object
)->getDataType();
741 * Get item by it's id
743 DCObject
*Template
::getDCObjectById(UINT32 itemId
, bool lock
)
745 DCObject
*object
= NULL
;
748 lockDciAccess(false);
750 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
752 DCObject
*curr
= m_dcObjects
->get(i
);
753 if (curr
->getId() == itemId
)
766 * Get item by template item id
768 DCObject
*Template
::getDCObjectByTemplateId(UINT32 tmplItemId
)
770 DCObject
*object
= NULL
;
772 lockDciAccess(false);
773 // Check if that item exists
774 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
776 DCObject
*curr
= m_dcObjects
->get(i
);
777 if (curr
->getTemplateItemId() == tmplItemId
)
789 * Get item by it's name (case-insensetive)
791 DCObject
*Template
::getDCObjectByName(const TCHAR
*name
)
793 DCObject
*object
= NULL
;
795 lockDciAccess(false);
796 // Check if that item exists
797 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
799 DCObject
*curr
= m_dcObjects
->get(i
);
800 if (!_tcsicmp(curr
->getName(), name
))
811 * Get item by it's description (case-insensetive)
813 DCObject
*Template
::getDCObjectByDescription(const TCHAR
*description
)
815 DCObject
*object
= NULL
;
817 lockDciAccess(false);
818 // Check if that item exists
819 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
821 DCObject
*curr
= m_dcObjects
->get(i
);
822 if (!_tcsicmp(curr
->getDescription(), description
))
835 DCObject
*Template
::getDCObjectByGUID(const uuid
& guid
, bool lock
)
837 DCObject
*object
= NULL
;
840 lockDciAccess(false);
842 // Check if that item exists
843 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
845 DCObject
*curr
= m_dcObjects
->get(i
);
846 if (guid
.equals(curr
->getGuid()))
859 * Get item by it's index
861 DCObject
*Template
::getDCObjectByIndex(int index
)
863 lockDciAccess(false);
864 DCObject
*object
= m_dcObjects
->get(index
);
870 * Get all DC objects with matching name and description
872 NXSL_Value
*Template
::getAllDCObjectsForNXSL(const TCHAR
*name
, const TCHAR
*description
)
874 NXSL_Array
*list
= new NXSL_Array();
875 lockDciAccess(false);
876 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
878 DCObject
*curr
= m_dcObjects
->get(i
);
879 if (((name
== NULL
) || MatchString(name
, curr
->getName(), false)) &&
880 ((description
== NULL
) || MatchString(description
, curr
->getDescription(), false)))
882 list
->set(list
->size(), curr
->createNXSLObject());
886 return new NXSL_Value(list
);
890 * Redefined status calculation for template
892 void Template
::calculateCompoundStatus(BOOL bForcedRecalc
)
894 m_status
= STATUS_NORMAL
;
898 * Create NXCP message with object's data
900 void Template
::fillMessageInternal(NXCPMessage
*pMsg
)
902 NetObj
::fillMessageInternal(pMsg
);
903 pMsg
->setField(VID_TEMPLATE_VERSION
, m_dwVersion
);
904 pMsg
->setField(VID_AUTOBIND_FILTER
, CHECK_NULL_EX(m_applyFilterSource
));
908 * Modify object from NXCP message
910 UINT32 Template
::modifyFromMessageInternal(NXCPMessage
*pRequest
)
912 // Skip modifications for subclasses
913 if (getObjectClass() != OBJECT_TEMPLATE
)
914 return NetObj
::modifyFromMessageInternal(pRequest
);
916 // Change template version
917 if (pRequest
->isFieldExist(VID_TEMPLATE_VERSION
))
918 m_dwVersion
= pRequest
->getFieldAsUInt32(VID_TEMPLATE_VERSION
);
921 if (pRequest
->isFieldExist(VID_FLAGS
))
923 UINT32 mask
= pRequest
->isFieldExist(VID_FLAGS_MASK
) ? pRequest
->getFieldAsUInt32(VID_FLAGS_MASK
) : 0xFFFFFFFF;
925 m_flags
|= pRequest
->getFieldAsUInt32(VID_FLAGS
) & mask
;
928 // Change apply filter
929 if (pRequest
->isFieldExist(VID_AUTOBIND_FILTER
))
931 free(m_applyFilterSource
);
932 delete m_applyFilter
;
933 m_applyFilterSource
= pRequest
->getFieldAsString(VID_AUTOBIND_FILTER
);
934 if (m_applyFilterSource
!= NULL
)
938 m_applyFilter
= NXSLCompile(m_applyFilterSource
, error
, 256, NULL
);
939 if (m_applyFilter
== NULL
)
942 _sntprintf(buffer
, 1024, _T("Template::%s::%d"), m_name
, m_id
);
943 PostEvent(EVENT_SCRIPT_ERROR
, g_dwMgmtNode
, "ssd", buffer
, error
, m_id
);
944 nxlog_write(MSG_TEMPLATE_SCRIPT_COMPILATION_ERROR
, EVENTLOG_WARNING_TYPE
, "dss", m_id
, m_name
, error
);
949 m_applyFilter
= NULL
;
953 return NetObj
::modifyFromMessageInternal(pRequest
);
957 * Apply template to data collection target
959 BOOL Template
::applyToTarget(DataCollectionTarget
*target
)
962 BOOL bErrors
= FALSE
;
964 // Link node to template
965 if (!isChild(target
->getId()))
968 target
->addParent(this);
971 pdwItemList
= (UINT32
*)malloc(sizeof(UINT32
) * m_dcObjects
->size());
972 DbgPrintf(2, _T("Apply %d items from template \"%s\" to target \"%s\""),
973 m_dcObjects
->size(), m_name
, target
->getName());
976 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
978 DCObject
*object
= m_dcObjects
->get(i
);
979 pdwItemList
[i
] = object
->getId();
980 if (!target
->applyTemplateItem(m_id
, object
))
986 // Clean items deleted from template
987 target
->cleanDeletedTemplateItems(m_id
, m_dcObjects
->size(), pdwItemList
);
992 target
->onDataCollectionChange();
994 // Queue update if target is a cluster
995 if (target
->getObjectClass() == OBJECT_CLUSTER
)
997 target
->queueUpdate();
1004 * Queue template update
1006 void Template
::queueUpdate()
1008 lockChildList(false);
1009 for(int i
= 0; i
< m_childList
->size(); i
++)
1011 NetObj
*object
= m_childList
->get(i
);
1012 if (object
->isDataCollectionTarget())
1015 TEMPLATE_UPDATE_INFO
*pInfo
= (TEMPLATE_UPDATE_INFO
*)malloc(sizeof(TEMPLATE_UPDATE_INFO
));
1016 pInfo
->updateType
= APPLY_TEMPLATE
;
1017 pInfo
->pTemplate
= this;
1018 pInfo
->targetId
= object
->getId();
1019 pInfo
->removeDCI
= false;
1020 g_templateUpdateQueue
.put(pInfo
);
1027 * Queue template remove from node
1029 void Template
::queueRemoveFromTarget(UINT32 targetId
, bool removeDCI
)
1033 TEMPLATE_UPDATE_INFO
*pInfo
= (TEMPLATE_UPDATE_INFO
*)malloc(sizeof(TEMPLATE_UPDATE_INFO
));
1034 pInfo
->updateType
= REMOVE_TEMPLATE
;
1035 pInfo
->pTemplate
= this;
1036 pInfo
->targetId
= targetId
;
1037 pInfo
->removeDCI
= removeDCI
;
1038 g_templateUpdateQueue
.put(pInfo
);
1043 * Get list of events used by DCIs
1045 IntegerArray
<UINT32
> *Template
::getDCIEventsList()
1047 IntegerArray
<UINT32
> *eventList
= new IntegerArray
<UINT32
>(64);
1048 lockDciAccess(false);
1049 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1051 m_dcObjects
->get(i
)->getEventList(eventList
);
1055 // Clean list from duplicates
1056 for(int i
= 0; i
< eventList
->size(); i
++)
1058 for(int j
= i
+ 1; j
< eventList
->size(); j
++)
1060 if (eventList
->get(i
) == eventList
->get(j
))
1062 eventList
->remove(j
);
1072 * Get list of scripts used by DCIs
1074 StringSet
*Template
::getDCIScriptList()
1076 StringSet
*list
= new StringSet
;
1078 lockDciAccess(false);
1079 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1081 DCObject
*o
= m_dcObjects
->get(i
);
1082 if (o
->getDataSource() == DS_SCRIPT
)
1084 const TCHAR
*name
= o
->getName();
1085 const TCHAR
*p
= _tcschr(name
, _T('('));
1089 nx_strncpy(buffer
, name
, p
- name
+ 1);
1103 * Create management pack record
1105 void Template
::createExportRecord(String
&str
)
1108 str
.appendFormattedString(_T("\t\t<template id=\"%d\">\n\t\t\t<guid>%s</guid>\n\t\t\t<name>%s</name>\n\t\t\t<flags>%d</flags>\n"),
1109 m_id
, m_guid
.toString(guid
), (const TCHAR
*)EscapeStringForXML2(m_name
), m_flags
);
1113 ObjectArray
<NetObj
> *list
= getParentList(OBJECT_TEMPLATEGROUP
);
1114 TemplateGroup
*parent
= NULL
;
1115 while(list
->size() > 0)
1117 parent
= (TemplateGroup
*)list
->get(0);
1118 path
.add(parent
->getName());
1120 list
= parent
->getParentList(OBJECT_TEMPLATEGROUP
);
1124 str
.append(_T("\t\t\t<path>\n"));
1125 for(int j
= path
.size() - 1, id
= 1; j
>= 0; j
--, id
++)
1127 str
.append(_T("\t\t\t\t<element id=\""));
1129 str
.append(_T("\">"));
1130 str
.append(path
.get(j
));
1131 str
.append(_T("</element>\n"));
1133 str
.append(_T("\t\t\t</path>\n\t\t\t<dataCollection>\n"));
1135 lockDciAccess(false);
1136 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1137 m_dcObjects
->get(i
)->createExportRecord(str
);
1140 str
.append(_T("\t\t\t</dataCollection>\n"));
1142 if (m_applyFilterSource
!= NULL
)
1144 str
.append(_T("\t\t\t<filter>"));
1145 str
.appendPreallocated(EscapeStringForXML(m_applyFilterSource
, -1));
1146 str
.append(_T("</filter>\n"));
1149 str
.append(_T("\t\t</template>\n"));
1153 * Enumerate all DCIs
1155 bool Template
::enumDCObjects(bool (* pfCallback
)(DCObject
*, UINT32
, void *), void *pArg
)
1157 bool success
= true;
1159 lockDciAccess(false);
1160 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1162 if (!pfCallback(m_dcObjects
->get(i
), i
, pArg
))
1173 * (Re)associate all DCIs
1175 void Template
::associateItems()
1177 lockDciAccess(false);
1178 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1179 m_dcObjects
->get(i
)->changeBinding(0, this, FALSE
);
1184 * Prepare template for deletion
1186 void Template
::prepareForDeletion()
1188 if (getObjectClass() == OBJECT_TEMPLATE
)
1190 lockChildList(false);
1191 for(int i
= 0; i
< m_childList
->size(); i
++)
1193 NetObj
*object
= m_childList
->get(i
);
1194 if (object
->isDataCollectionTarget())
1195 queueRemoveFromTarget(object
->getId(), true);
1199 NetObj
::prepareForDeletion();
1203 * Check if template should be automatically applied to given data collection target
1204 * Returns AutoBindDecision_Bind if applicable, AutoBindDecision_Unbind if not,
1205 * AutoBindDecision_Ignore if no change required (script error or no auto apply)
1207 AutoBindDecision Template
::isApplicable(DataCollectionTarget
*target
)
1209 AutoBindDecision result
= AutoBindDecision_Ignore
;
1211 NXSL_VM
*filter
= NULL
;
1213 if ((m_flags
& TF_AUTO_APPLY
) && (m_applyFilter
!= NULL
))
1215 filter
= new NXSL_VM(new NXSL_ServerEnv());
1216 if (!filter
->load(m_applyFilter
))
1219 _sntprintf(buffer
, 1024, _T("Template::%s::%d"), m_name
, m_id
);
1220 PostEvent(EVENT_SCRIPT_ERROR
, g_dwMgmtNode
, "ssd", buffer
, filter
->getErrorText(), m_id
);
1221 nxlog_write(MSG_TEMPLATE_SCRIPT_EXECUTION_ERROR
, EVENTLOG_WARNING_TYPE
, "dss", m_id
, m_name
, filter
->getErrorText());
1222 delete_and_null(filter
);
1230 filter
->setGlobalVariable(_T("$object"), target
->createNXSLObject());
1231 if (target
->getObjectClass() == OBJECT_NODE
)
1232 filter
->setGlobalVariable(_T("$node"), target
->createNXSLObject());
1235 NXSL_Value
*value
= filter
->getResult();
1236 if (!value
->isNull())
1237 result
= ((value
!= NULL
) && (value
->getValueAsInt32() != 0)) ? AutoBindDecision_Bind
: AutoBindDecision_Unbind
;
1243 _sntprintf(buffer
, 1024, _T("Template::%s::%d"), m_name
, m_id
);
1244 PostEvent(EVENT_SCRIPT_ERROR
, g_dwMgmtNode
, "ssd", buffer
, filter
->getErrorText(), m_id
);
1245 nxlog_write(MSG_TEMPLATE_SCRIPT_EXECUTION_ERROR
, EVENTLOG_WARNING_TYPE
, "dss", m_id
, m_name
, filter
->getErrorText());
1253 * Get last (current) DCI values. Moved to Template from DataCollectionTarget to allow
1254 * simplified creation of DCI selection dialog in management console. For classes not
1255 * derived from DataCollectionTarget actual values will always be empty strings
1256 * with data type DCI_DT_NULL.
1258 UINT32 Template
::getLastValues(NXCPMessage
*msg
, bool objectTooltipOnly
, bool overviewOnly
, bool includeNoValueObjects
)
1260 lockDciAccess(false);
1262 UINT32 dwId
= VID_DCI_VALUES_BASE
, dwCount
= 0;
1263 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1265 DCObject
*object
= m_dcObjects
->get(i
);
1266 if ((object
->hasValue() || includeNoValueObjects
) &&
1267 (!objectTooltipOnly
|| object
->isShowOnObjectTooltip()) &&
1268 (!overviewOnly
|| object
->isShowInObjectOverview()))
1270 if (object
->getType() == DCO_TYPE_ITEM
)
1272 ((DCItem
*)object
)->fillLastValueMessage(msg
, dwId
);
1276 else if (object
->getType() == DCO_TYPE_TABLE
)
1278 ((DCTable
*)object
)->fillLastValueSummaryMessage(msg
, dwId
);
1284 msg
->setField(VID_NUM_ITEMS
, dwCount
);
1291 * Called when data collection configuration changed
1293 void Template
::onDataCollectionChange()
1295 // Do not queue updates for subclasses
1296 if (getObjectClass() == OBJECT_TEMPLATE
)
1301 * Update template from import
1303 void Template
::updateFromImport(ConfigEntry
*config
)
1307 m_dwVersion
= config
->getSubEntryValueAsUInt(_T("version"), 0, m_dwVersion
);
1308 m_flags
= config
->getSubEntryValueAsUInt(_T("flags"), 0, m_flags
);
1311 // Auto-apply filter
1312 setAutoApplyFilter(config
->getSubEntryValue(_T("filter")));
1315 ObjectArray
<uuid
> guidList(32, 32, true);
1317 lockDciAccess(true);
1318 ConfigEntry
*dcRoot
= config
->findEntry(_T("dataCollection"));
1321 ObjectArray
<ConfigEntry
> *dcis
= dcRoot
->getSubEntries(_T("dci#*"));
1322 for(int i
= 0; i
< dcis
->size(); i
++)
1324 ConfigEntry
*e
= dcis
->get(i
);
1325 uuid guid
= e
->getSubEntryValueAsUUID(_T("guid"));
1326 DCObject
*curr
= !guid
.isNull() ?
getDCObjectByGUID(guid
, false) : NULL
;
1327 if ((curr
!= NULL
) && (curr
->getType() == DCO_TYPE_ITEM
))
1329 curr
->updateFromImport(e
);
1333 m_dcObjects
->add(new DCItem(e
, this));
1335 guidList
.add(new uuid(guid
));
1339 ObjectArray
<ConfigEntry
> *dctables
= dcRoot
->getSubEntries(_T("dctable#*"));
1340 for(int i
= 0; i
< dctables
->size(); i
++)
1342 ConfigEntry
*e
= dctables
->get(i
);
1343 uuid guid
= e
->getSubEntryValueAsUUID(_T("guid"));
1344 DCObject
*curr
= !guid
.isNull() ?
getDCObjectByGUID(guid
, false) : NULL
;
1345 if ((curr
!= NULL
) && (curr
->getType() == DCO_TYPE_TABLE
))
1347 curr
->updateFromImport(e
);
1351 m_dcObjects
->add(new DCTable(e
, this));
1353 guidList
.add(new uuid(guid
));
1358 // Delete DCIs missing in import
1359 IntegerArray
<UINT32
> deleteList
;
1360 for(int i
= 0; i
< m_dcObjects
->size(); i
++)
1363 for(int j
= 0; j
< guidList
.size(); j
++)
1365 if (guidList
.get(j
)->equals(m_dcObjects
->get(i
)->getGuid()))
1374 deleteList
.add(m_dcObjects
->get(i
)->getId());
1378 for(int i
= 0; i
< deleteList
.size(); i
++)
1379 deleteDCObject(deleteList
.get(i
), false);
1387 * Serialize object to JSON
1389 json_t
*Template
::toJson()
1391 json_t
*root
= NetObj
::toJson();
1392 json_object_set_new(root
, "dcObjects", json_object_array(m_dcObjects
));
1393 json_object_set_new(root
, "version", json_integer(m_dwVersion
));
1394 json_object_set_new(root
, "flags", json_integer(m_flags
));
1395 json_object_set_new(root
, "applyFilter", json_string_t(m_applyFilterSource
));