fixed bug in instance discovery DCI deletion
[public/netxms.git] / src / server / core / template.cpp
CommitLineData
4016c0df 1/*
5039dede 2** NetXMS - Network Management System
615621a4 3** Copyright (C) 2003-2016 Victor Kirhenshtein
5039dede
AK
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: template.cpp
20**
21**/
22
23#include "nxcore.h"
24
6fd6de0a
VK
25/**
26 * Redefined status calculation for template group
27 */
27f9598d 28void TemplateGroup::calculateCompoundStatus(BOOL bForcedRecalc)
5039dede 29{
db091a1f 30 m_status = STATUS_NORMAL;
5039dede
AK
31}
32
27bbb906
VK
33/**
34 * Called by client session handler to check if threshold summary should be shown for this object.
35 */
36bool TemplateGroup::showThresholdSummary()
37{
38 return false;
39}
40
6fd6de0a
VK
41/**
42 * Template object constructor
43 */
16d6f798 44Template::Template() : NetObj()
5039dede 45{
16d6f798 46 m_dcObjects = new ObjectArray<DCObject>(8, 16, true);
2a964810 47 m_dciLockStatus = -1;
feab3324 48 m_flags = 0;
5039dede 49 m_dwVersion = 0x00010000; // Initial version is 1.0
4d0c32f3
VK
50 m_applyFilter = NULL;
51 m_applyFilterSource = NULL;
db091a1f 52 m_status = STATUS_NORMAL;
b06436f4 53 m_dciAccessLock = RWLockCreate();
9fd816cc 54 m_dciListModified = false;
5039dede
AK
55}
56
6fd6de0a
VK
57/**
58 * Constructor for new template object
59 */
16d6f798 60Template::Template(const TCHAR *pszName) : NetObj()
5039dede 61{
c42b4551 62 nx_strncpy(m_name, pszName, MAX_OBJECT_NAME);
16d6f798 63 m_dcObjects = new ObjectArray<DCObject>(8, 16, true);
2a964810 64 m_dciLockStatus = -1;
feab3324 65 m_flags = 0;
5039dede 66 m_dwVersion = 0x00010000; // Initial version is 1.0
4d0c32f3
VK
67 m_applyFilter = NULL;
68 m_applyFilterSource = NULL;
db091a1f 69 m_status = STATUS_NORMAL;
01152a54 70 m_isHidden = true;
b06436f4 71 m_dciAccessLock = RWLockCreate();
9fd816cc 72 m_dciListModified = false;
5039dede
AK
73}
74
892aaefa
VK
75/**
76 * Create template object from import file
77 */
16d6f798 78Template::Template(ConfigEntry *config) : NetObj()
a65c1819 79{
01152a54 80 m_isHidden = true;
2a964810 81 m_dciLockStatus = -1;
db091a1f 82 m_status = STATUS_NORMAL;
b06436f4 83 m_dciAccessLock = RWLockCreate();
9fd816cc 84 m_dciListModified = false;
a65c1819 85
98ef8e4a
VK
86 // GUID
87 uuid guid = config->getSubEntryValueAsUUID(_T("guid"));
88 if (!guid.isNull())
89 m_guid = guid;
90
a65c1819 91 // Name and version
c42b4551 92 nx_strncpy(m_name, config->getSubEntryValue(_T("name"), 0, _T("Unnamed Template")), MAX_OBJECT_NAME);
31b0f68b
VK
93 m_dwVersion = config->getSubEntryValueAsUInt(_T("version"), 0, 0x00010000);
94 m_flags = config->getSubEntryValueAsUInt(_T("flags"), 0, 0);
a65c1819
VK
95
96 // Auto-apply filter
97 m_applyFilter = NULL;
98 m_applyFilterSource = NULL;
feab3324
VK
99 if (m_flags & TF_AUTO_APPLY)
100 setAutoApplyFilter(config->getSubEntryValue(_T("filter")));
a65c1819
VK
101
102 // Data collection
16d6f798 103 m_dcObjects = new ObjectArray<DCObject>(8, 16, true);
a65c1819
VK
104 ConfigEntry *dcRoot = config->findEntry(_T("dataCollection"));
105 if (dcRoot != NULL)
106 {
8b7ae7eb
VK
107 ObjectArray<ConfigEntry> *dcis = dcRoot->getSubEntries(_T("dci#*"));
108 for(int i = 0; i < dcis->size(); i++)
a65c1819 109 {
8b7ae7eb 110 m_dcObjects->add(new DCItem(dcis->get(i), this));
a65c1819
VK
111 }
112 delete dcis;
9387bc59 113
8b7ae7eb
VK
114 ObjectArray<ConfigEntry> *dctables = dcRoot->getSubEntries(_T("dctable#*"));
115 for(int i = 0; i < dctables->size(); i++)
9387bc59 116 {
8b7ae7eb 117 m_dcObjects->add(new DCTable(dctables->get(i), this));
9387bc59
VK
118 }
119 delete dctables;
120 }
a65c1819
VK
121}
122
892aaefa
VK
123/**
124 * Destructor
125 */
5039dede
AK
126Template::~Template()
127{
16d6f798 128 delete m_dcObjects;
4d0c32f3
VK
129 delete m_applyFilter;
130 safe_free(m_applyFilterSource);
b06436f4 131 RWLockDestroy(m_dciAccessLock);
5039dede
AK
132}
133
892aaefa
VK
134/**
135 * Destroy all related data collection items.
136 */
7c521895 137void Template::destroyItems()
5039dede 138{
16d6f798 139 m_dcObjects->clear();
5039dede
AK
140}
141
892aaefa
VK
142/**
143 * Set auto apply filter.
144 *
145 * @param filter new filter script code or NULL to clear filter
146 */
fb05c05b
VK
147void Template::setAutoApplyFilter(const TCHAR *filter)
148{
c42b4551 149 lockProperties();
fb05c05b
VK
150 safe_free(m_applyFilterSource);
151 delete m_applyFilter;
152 if (filter != NULL)
153 {
154 TCHAR error[256];
155
156 m_applyFilterSource = _tcsdup(filter);
9fc9ec2c 157 m_applyFilter = NXSLCompile(m_applyFilterSource, error, 256, NULL);
fb05c05b 158 if (m_applyFilter == NULL)
615621a4
VK
159 {
160 TCHAR buffer[1024];
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);
164 }
fb05c05b
VK
165 }
166 else
167 {
168 m_applyFilterSource = NULL;
169 m_applyFilter = NULL;
170 }
c42b4551
VK
171 setModified();
172 unlockProperties();
fb05c05b
VK
173}
174
892aaefa
VK
175/**
176 * Create template object from database data
177 *
178 * @param dwId object ID
179 */
9bd1bace 180bool Template::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
5039dede
AK
181{
182 TCHAR szQuery[256];
967893bb 183 UINT32 i, dwNumNodes, dwNodeId;
5039dede 184 NetObj *pObject;
5039dede 185
c42b4551 186 m_id = dwId;
5039dede 187
9bd1bace 188 if (!loadCommonProperties(hdb))
a2fb825b 189 return false;
5039dede 190
feab3324 191 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("SELECT version,flags,apply_filter FROM templates WHERE id=%d"), dwId);
a2fb825b 192 DB_RESULT hResult = DBSelect(hdb, szQuery);
5039dede 193 if (hResult == NULL)
a2fb825b 194 return false;
5039dede
AK
195
196 if (DBGetNumRows(hResult) == 0)
197 {
198 // No object with given ID in database
199 DBFreeResult(hResult);
a2fb825b 200 return false;
5039dede
AK
201 }
202
a2fb825b
VK
203 bool success = true;
204
5039dede 205 m_dwVersion = DBGetFieldULong(hResult, 0, 0);
feab3324 206 m_flags = DBGetFieldULong(hResult, 0, 1);
4734707c
VK
207 m_applyFilterSource = DBGetField(hResult, 0, 2, NULL, 0);
208 if (m_applyFilterSource != NULL)
209 {
210 TCHAR error[256];
211 m_applyFilter = NXSLCompile(m_applyFilterSource, error, 256, NULL);
212 if (m_applyFilter == NULL)
615621a4
VK
213 {
214 TCHAR buffer[1024];
215 _sntprintf(buffer, 1024, _T("Template::%s::%d"), m_name, m_id);
216 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, error, m_id);
4734707c 217 nxlog_write(MSG_TEMPLATE_SCRIPT_COMPILATION_ERROR, EVENTLOG_WARNING_TYPE, "dss", m_id, m_name, error);
615621a4 218 }
4734707c 219 }
5039dede
AK
220 DBFreeResult(hResult);
221
222 // Load DCI and access list
9bd1bace
VK
223 loadACLFromDB(hdb);
224 loadItemsFromDB(hdb);
967893bb 225 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
9bd1bace 226 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
a2fb825b 227 success = false;
5039dede
AK
228
229 // Load related nodes list
01152a54 230 if (!m_isDeleted)
5039dede 231 {
c42b4551 232 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("SELECT node_id FROM dct_node_map WHERE template_id=%d"), m_id);
9bd1bace 233 hResult = DBSelect(hdb, szQuery);
5039dede
AK
234 if (hResult != NULL)
235 {
236 dwNumNodes = DBGetNumRows(hResult);
237 for(i = 0; i < dwNumNodes; i++)
238 {
239 dwNodeId = DBGetFieldULong(hResult, i, 0);
240 pObject = FindObjectById(dwNodeId);
241 if (pObject != NULL)
242 {
c42b4551 243 if ((pObject->getObjectClass() == OBJECT_NODE) || (pObject->getObjectClass() == OBJECT_CLUSTER) || (pObject->getObjectClass() == OBJECT_MOBILEDEVICE))
5039dede 244 {
1f8be1f4
VK
245 addChild(pObject);
246 pObject->addParent(this);
5039dede
AK
247 }
248 else
249 {
c42b4551 250 nxlog_write(MSG_DCT_MAP_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", m_id, dwNodeId);
5039dede
AK
251 }
252 }
253 else
254 {
c42b4551 255 nxlog_write(MSG_INVALID_DCT_MAP, EVENTLOG_ERROR_TYPE, "dd", m_id, dwNodeId);
5039dede
AK
256 }
257 }
258 DBFreeResult(hResult);
259 }
260 }
261
db091a1f 262 m_status = STATUS_NORMAL;
926e8ce7 263
a2fb825b 264 return success;
5039dede
AK
265}
266
f05a8a45
VK
267/**
268 * Save object to database
269 */
c42b4551 270BOOL Template::saveToDatabase(DB_HANDLE hdb)
5039dede 271{
c42b4551 272 lockProperties();
5039dede 273
feab3324
VK
274 if (!saveCommonProperties(hdb))
275 {
c42b4551 276 unlockProperties();
feab3324
VK
277 return FALSE;
278 }
5039dede 279
feab3324 280 DB_STATEMENT hStmt;
c42b4551 281 if (IsDatabaseRecordExist(hdb, _T("templates"), _T("id"), m_id))
ba89fed2 282 {
feab3324 283 hStmt = DBPrepare(hdb, _T("UPDATE templates SET version=?,flags=?,apply_filter=? WHERE id=?"));
ba89fed2
VK
284 }
285 else
286 {
feab3324 287 hStmt = DBPrepare(hdb, _T("INSERT INTO templates (version,flags,apply_filter,id) VALUES (?,?,?,?)"));
ba89fed2 288 }
feab3324
VK
289 if (hStmt == NULL)
290 {
c42b4551 291 unlockProperties();
feab3324
VK
292 return FALSE;
293 }
294
295 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwVersion);
296 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_flags);
297 DBBind(hStmt, 3, DB_SQLTYPE_TEXT, m_applyFilterSource, DB_BIND_STATIC);
c42b4551 298 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_id);
feab3324
VK
299 BOOL success = DBExecute(hStmt);
300 DBFreeStatement(hStmt);
301
302 if (success)
303 {
304 TCHAR query[256];
305
306 // Update members list
c42b4551 307 _sntprintf(query, 256, _T("DELETE FROM dct_node_map WHERE template_id=%d"), m_id);
feab3324 308 DBQuery(hdb, query);
db091a1f
VK
309 lockChildList(false);
310 for(int i = 0; i < m_childList->size(); i++)
feab3324 311 {
db091a1f 312 _sntprintf(query, 256, _T("INSERT INTO dct_node_map (template_id,node_id) VALUES (%d,%d)"), m_id, m_childList->get(i)->getId());
feab3324
VK
313 DBQuery(hdb, query);
314 }
db091a1f 315 unlockChildList();
5039dede 316
feab3324
VK
317 // Save access list
318 saveACLToDB(hdb);
319 }
7c521895 320
c42b4551 321 unlockProperties();
7c521895 322
5039dede 323 // Save data collection items
b06436f4 324 lockDciAccess(false);
feab3324 325 for(int i = 0; i < m_dcObjects->size(); i++)
e7450f3b 326 m_dcObjects->get(i)->saveToDatabase(hdb);
7c521895 327 unlockDciAccess();
5039dede 328
7c521895 329 // Clear modifications flag
c42b4551 330 lockProperties();
01152a54 331 m_isModified = false;
c42b4551 332 unlockProperties();
5039dede 333
feab3324 334 return success;
5039dede
AK
335}
336
f05a8a45
VK
337/**
338 * Delete object from database
339 */
c42b4551 340bool Template::deleteFromDatabase(DB_HANDLE hdb)
5039dede 341{
c42b4551 342 bool success = NetObj::deleteFromDatabase(hdb);
22ee6d97 343 if (success)
5039dede 344 {
c42b4551 345 if (getObjectClass() == OBJECT_TEMPLATE)
5039dede 346 {
22ee6d97
VK
347 success = executeQueryOnObject(hdb, _T("DELETE FROM templates WHERE id=?"));
348 if (success)
349 success = executeQueryOnObject(hdb, _T("DELETE FROM dct_node_map WHERE template_id=?"));
5039dede
AK
350 }
351 else
352 {
22ee6d97 353 success = executeQueryOnObject(hdb, _T("DELETE FROM dct_node_map WHERE node_id=?"));
5039dede 354 }
22ee6d97
VK
355 if (success)
356 success = executeQueryOnObject(hdb, _T("DELETE FROM items WHERE node_id=?"));
357 if (success)
358 success = executeQueryOnObject(hdb, _T("UPDATE items SET template_id=0 WHERE template_id=?"));
5039dede 359 }
22ee6d97 360 return success;
5039dede
AK
361}
362
f05a8a45
VK
363/**
364 * Load data collection items from database
365 */
9bd1bace 366void Template::loadItemsFromDB(DB_HANDLE hdb)
5039dede 367{
9bd1bace 368 DB_STATEMENT hStmt = DBPrepare(hdb,
4d0c32f3
VK
369 _T("SELECT item_id,name,source,datatype,polling_interval,retention_time,")
370 _T("status,delta_calculation,transformation,template_id,description,")
e320f8ce 371 _T("instance,template_item_id,flags,resource_id,")
4d0c32f3 372 _T("proxy_node,base_units,unit_multiplier,custom_units_name,")
afbe5388 373 _T("perftab_settings,system_tag,snmp_port,snmp_raw_value_type,")
98ef8e4a 374 _T("instd_method,instd_data,instd_filter,samples,comments,guid FROM items WHERE node_id=?"));
92c51b1d
VK
375 if (hStmt != NULL)
376 {
c42b4551 377 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
92c51b1d
VK
378 DB_RESULT hResult = DBSelectPrepared(hStmt);
379 if (hResult != NULL)
380 {
381 int count = DBGetNumRows(hResult);
382 for(int i = 0; i < count; i++)
9bd1bace 383 m_dcObjects->add(new DCItem(hdb, hResult, i, this));
92c51b1d
VK
384 DBFreeResult(hResult);
385 }
386 DBFreeStatement(hStmt);
387 }
ba89fed2 388
9bd1bace 389 hStmt = DBPrepare(hdb,
22aaa779 390 _T("SELECT item_id,template_id,template_item_id,name,")
ba89fed2 391 _T("description,flags,source,snmp_port,polling_interval,retention_time,")
b6005694 392 _T("status,system_tag,resource_id,proxy_node,perftab_settings,")
6388e079 393 _T("transformation_script,comments,guid FROM dc_tables WHERE node_id=?"));
92c51b1d
VK
394 if (hStmt != NULL)
395 {
c42b4551 396 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
92c51b1d
VK
397 DB_RESULT hResult = DBSelectPrepared(hStmt);
398 if (hResult != NULL)
399 {
400 int count = DBGetNumRows(hResult);
401 for(int i = 0; i < count; i++)
9bd1bace 402 m_dcObjects->add(new DCTable(hdb, hResult, i, this));
92c51b1d
VK
403 DBFreeResult(hResult);
404 }
405 DBFreeStatement(hStmt);
406 }
5039dede
AK
407}
408
f05a8a45
VK
409/**
410 * Add data collection object to node
411 */
16d6f798 412bool Template::addDCObject(DCObject *object, bool alreadyLocked)
5039dede 413{
16d6f798 414 int i;
7c521895 415 bool success = false;
5039dede 416
7c521895 417 if (!alreadyLocked)
b06436f4 418 lockDciAccess(true); // write lock
5039dede 419
16d6f798
VK
420 // Check if that object exists
421 for(i = 0; i < m_dcObjects->size(); i++)
422 if (m_dcObjects->get(i)->getId() == object->getId())
423 break; // Object with specified id already exist
4016c0df 424
16d6f798 425 if (i == m_dcObjects->size()) // Add new item
5039dede 426 {
16d6f798
VK
427 m_dcObjects->add(object);
428 object->setLastPollTime(0); // Cause item to be polled immediatelly
429 if (object->getStatus() != ITEM_STATUS_DISABLED)
430 object->setStatus(ITEM_STATUS_ACTIVE, false);
431 object->setBusyFlag(FALSE);
4064eff3 432 m_isModified = true;
7c521895 433 success = true;
5039dede
AK
434 }
435
7c521895
VK
436 if (!alreadyLocked)
437 unlockDciAccess();
438
439 if (success)
440 {
c42b4551
VK
441 lockProperties();
442 setModified();
443 unlockProperties();
7c521895
VK
444 }
445 return success;
5039dede
AK
446}
447
d51f2182
VK
448/**
449 * Delete data collection object from node
450 */
967893bb 451bool Template::deleteDCObject(UINT32 dcObjectId, bool needLock)
5039dede 452{
7c521895 453 bool success = false;
5039dede 454
7c521895 455 if (needLock)
b06436f4 456 lockDciAccess(true); // write lock
5039dede
AK
457
458 // Check if that item exists
16d6f798
VK
459 for(int i = 0; i < m_dcObjects->size(); i++)
460 {
461 DCObject *object = m_dcObjects->get(i);
462 if (object->getId() == dcObjectId)
5039dede 463 {
2ceba9df
VK
464 // Check if it is instance DCI
465 if ((object->getType() == DCO_TYPE_ITEM) && (((DCItem *)object)->getInstanceDiscoveryMethod() != IDM_NONE))
9fcf5d15 466 {
467 deleteChildDCIs(dcObjectId);
cd6447b6
VK
468
469 // Index may be incorrect at this point
470 if (m_dcObjects->get(i) != object)
471 i = m_dcObjects->indexOf(object);
9fcf5d15 472 }
5039dede 473 // Destroy item
c42b4551 474 DbgPrintf(7, _T("Template::DeleteDCObject: deleting DCObject %d from object %d"), (int)dcObjectId, (int)m_id);
9fcf5d15 475 destroyItem(object, i);
4064eff3 476 m_isModified = true;
7c521895 477 success = true;
c42b4551 478 DbgPrintf(7, _T("Template::DeleteDCObject: DCO deleted from object %d"), (int)m_id);
5039dede
AK
479 break;
480 }
16d6f798 481 }
5039dede 482
7c521895
VK
483 if (needLock)
484 unlockDciAccess();
485 return success;
5039dede
AK
486}
487
9fcf5d15 488/**
489 * Delets child DCI objects of instance discovery DCI.
490 * It is assumed that list is already locked
491 */
492void Template::deleteChildDCIs(UINT32 dcObjectId)
493{
494 for(int i = 0; i < m_dcObjects->size(); i++)
495 {
496 DCObject *subObject = m_dcObjects->get(i);
497 if (subObject->getTemplateItemId() == dcObjectId)
498 {
499 destroyItem(subObject, i);
500 i--;
c42b4551 501 DbgPrintf(7, _T("Template::DeleteDCObject: deleting DCObject %d created by DCObject %d instance discovery from object %d"), (int)subObject->getId(), (int)dcObjectId, (int)m_id);
9fcf5d15 502 }
503 }
504}
505
506/**
c6e191d2
VK
507 * Delete DCI object.
508 * Deletes or schedules deletion from DB and removes it from index
9fcf5d15 509 * It is assumed that list is already locked
510 */
511void Template::destroyItem(DCObject *object, int index)
512{
513 if (object->prepareForDeletion())
514 {
515 // Physically delete DCI only if it is not busy
516 // Busy DCIs will be deleted by data collector
c42b4551 517 object->deleteFromDatabase();
9fcf5d15 518 m_dcObjects->remove(index);
519 }
520 else
521 {
522 m_dcObjects->unlink(index);
523 DbgPrintf(7, _T("Template::DeleteItem: destruction of DCO %d delayed"), (int)object->getId());
524 }
525}
526
d51f2182
VK
527/**
528 * Modify data collection object from NXCP message
529 */
b368969c 530bool Template::updateDCObject(UINT32 dwItemId, NXCPMessage *pMsg, UINT32 *pdwNumMaps, UINT32 **ppdwMapIndex, UINT32 **ppdwMapId)
5039dede 531{
7c521895 532 bool success = false;
5039dede 533
b06436f4 534 lockDciAccess(false);
5039dede
AK
535
536 // Check if that item exists
16d6f798
VK
537 for(int i = 0; i < m_dcObjects->size(); i++)
538 {
539 DCObject *object = m_dcObjects->get(i);
540 if (object->getId() == dwItemId)
5039dede 541 {
16d6f798
VK
542 if (object->getType() == DCO_TYPE_ITEM)
543 {
544 ((DCItem *)object)->updateFromMessage(pMsg, pdwNumMaps, ppdwMapIndex, ppdwMapId);
e46d6c36
VK
545 if (((DCItem *)object)->getInstanceDiscoveryMethod() != IDM_NONE)
546 {
547 updateInstanceDiscoveryItems((DCItem *)object);
548 }
16d6f798 549 }
e6a28e20
VK
550 else
551 {
552 object->updateFromMessage(pMsg);
553 }
554 success = true;
01152a54 555 m_isModified = true;
5039dede
AK
556 break;
557 }
16d6f798 558 }
5039dede 559
7c521895
VK
560 unlockDciAccess();
561 return success;
5039dede
AK
562}
563
e46d6c36
VK
564/**
565 * Update DCIs created by instance dicovery.
566 * This method expects DCI access already locked.
567 *
568 * @param dci instance discovery template DCI
569 */
570void Template::updateInstanceDiscoveryItems(DCItem *dci)
571{
572 for(int i = 0; i < m_dcObjects->size(); i++)
573 {
574 DCObject *object = m_dcObjects->get(i);
c42b4551 575 if ((object->getType() == DCO_TYPE_ITEM) && (object->getTemplateId() == m_id) && (object->getTemplateItemId() == dci->getId()))
e46d6c36
VK
576 {
577 object->updateFromTemplate(dci);
578 }
579 }
580}
581
f05a8a45
VK
582/**
583 * Set status for group of DCIs
584 */
967893bb 585bool Template::setItemStatus(UINT32 dwNumItems, UINT32 *pdwItemList, int iStatus)
5039dede 586{
7c521895 587 bool success = true;
5039dede 588
b06436f4 589 lockDciAccess(false);
967893bb 590 for(UINT32 i = 0; i < dwNumItems; i++)
5039dede 591 {
16d6f798
VK
592 int j;
593 for(j = 0; j < m_dcObjects->size(); j++)
5039dede 594 {
16d6f798 595 if (m_dcObjects->get(j)->getId() == pdwItemList[i])
5039dede 596 {
16d6f798 597 m_dcObjects->get(j)->setStatus(iStatus, true);
5039dede
AK
598 break;
599 }
600 }
16d6f798 601 if (j == m_dcObjects->size())
7c521895 602 success = false; // Invalid DCI ID provided
5039dede 603 }
7c521895
VK
604 unlockDciAccess();
605 return success;
5039dede
AK
606}
607
6fd6de0a
VK
608/**
609 * Lock data collection items list
610 */
9fd816cc 611bool Template::lockDCIList(int sessionId, const TCHAR *pszNewOwner, TCHAR *pszCurrOwner)
5039dede 612{
9fd816cc 613 bool success;
5039dede 614
c42b4551 615 lockProperties();
2a964810 616 if (m_dciLockStatus == -1)
5039dede 617 {
2a964810 618 m_dciLockStatus = sessionId;
9fd816cc 619 m_dciListModified = false;
5039dede 620 nx_strncpy(m_szCurrDCIOwner, pszNewOwner, MAX_SESSION_NAME);
9fd816cc 621 success = true;
5039dede
AK
622 }
623 else
624 {
625 if (pszCurrOwner != NULL)
626 _tcscpy(pszCurrOwner, m_szCurrDCIOwner);
9fd816cc 627 success = false;
5039dede 628 }
c42b4551 629 unlockProperties();
9fd816cc 630 return success;
5039dede
AK
631}
632
6fd6de0a
VK
633/**
634 * Unlock data collection items list
635 */
9fd816cc 636bool Template::unlockDCIList(int sessionId)
5039dede 637{
9fd816cc
VK
638 bool success = false;
639 bool callChangeHook = false;
5039dede 640
c42b4551 641 lockProperties();
2a964810 642 if (m_dciLockStatus == sessionId)
5039dede 643 {
2a964810 644 m_dciLockStatus = -1;
9fd816cc 645 if (m_dciListModified)
5039dede 646 {
1fa2ca0e
VK
647 if (getObjectClass() == OBJECT_TEMPLATE)
648 m_dwVersion++;
c42b4551 649 setModified();
9fd816cc 650 callChangeHook = true;
5039dede 651 }
9fd816cc
VK
652 m_dciListModified = false;
653 success = true;
5039dede 654 }
c42b4551 655 unlockProperties();
9fd816cc
VK
656
657 if (callChangeHook)
658 onDataCollectionChange();
659
660 return success;
5039dede
AK
661}
662
6fd6de0a
VK
663/**
664 * Send DCI list to client
665 */
967893bb 666void Template::sendItemsToClient(ClientSession *pSession, UINT32 dwRqId)
5039dede 667{
b368969c 668 NXCPMessage msg;
5039dede
AK
669
670 // Prepare message
b368969c
VK
671 msg.setId(dwRqId);
672 msg.setCode(CMD_NODE_DCI);
5039dede 673
b06436f4 674 lockDciAccess(false);
5039dede
AK
675
676 // Walk through items list
16d6f798 677 for(int i = 0; i < m_dcObjects->size(); i++)
5039dede 678 {
26d0c19b
VK
679 m_dcObjects->get(i)->createMessage(&msg);
680 pSession->sendMessage(&msg);
b368969c 681 msg.deleteAllFields();
5039dede
AK
682 }
683
7c521895 684 unlockDciAccess();
5039dede
AK
685
686 // Send end-of-list indicator
4af351c7 687 msg.setEndOfSequence();
e05b1945 688 pSession->sendMessage(&msg);
5039dede
AK
689}
690
f05a8a45
VK
691/**
692 * Get DCI's data type
693 */
967893bb 694int Template::getItemType(UINT32 dwItemId)
5039dede 695{
5039dede
AK
696 int iType = -1;
697
b06436f4 698 lockDciAccess(false);
5039dede 699 // Check if that item exists
16d6f798
VK
700 for(int i = 0; i < m_dcObjects->size(); i++)
701 {
702 DCObject *object = m_dcObjects->get(i);
703 if (object->getId() == dwItemId)
5039dede 704 {
16d6f798
VK
705 if (object->getType() == DCO_TYPE_ITEM)
706 {
707 iType = ((DCItem *)object)->getDataType();
708 }
5039dede
AK
709 break;
710 }
16d6f798 711 }
5039dede 712
7c521895 713 unlockDciAccess();
5039dede
AK
714 return iType;
715}
716
f05a8a45
VK
717/**
718 * Get item by it's id
719 */
0719f017 720DCObject *Template::getDCObjectById(UINT32 itemId, bool lock)
5039dede 721{
16d6f798 722 DCObject *object = NULL;
5039dede 723
0719f017
VK
724 if (lock)
725 lockDciAccess(false);
726
16d6f798
VK
727 for(int i = 0; i < m_dcObjects->size(); i++)
728 {
729 DCObject *curr = m_dcObjects->get(i);
85ae39bc
VK
730 if (curr->getId() == itemId)
731 {
732 object = curr;
733 break;
734 }
735 }
736
0719f017
VK
737 if (lock)
738 unlockDciAccess();
85ae39bc
VK
739 return object;
740}
741
742/**
743 * Get item by template item id
744 */
967893bb 745DCObject *Template::getDCObjectByTemplateId(UINT32 tmplItemId)
85ae39bc
VK
746{
747 DCObject *object = NULL;
748
b06436f4 749 lockDciAccess(false);
85ae39bc
VK
750 // Check if that item exists
751 for(int i = 0; i < m_dcObjects->size(); i++)
752 {
753 DCObject *curr = m_dcObjects->get(i);
754 if (curr->getTemplateItemId() == tmplItemId)
16d6f798
VK
755 {
756 object = curr;
5039dede 757 break;
16d6f798
VK
758 }
759 }
5039dede 760
7c521895 761 unlockDciAccess();
16d6f798 762 return object;
5039dede
AK
763}
764
f05a8a45
VK
765/**
766 * Get item by it's name (case-insensetive)
767 */
abb85c62 768DCObject *Template::getDCObjectByName(const TCHAR *name)
5039dede 769{
16d6f798 770 DCObject *object = NULL;
5039dede 771
b06436f4 772 lockDciAccess(false);
5039dede 773 // Check if that item exists
16d6f798
VK
774 for(int i = 0; i < m_dcObjects->size(); i++)
775 {
776 DCObject *curr = m_dcObjects->get(i);
abb85c62 777 if (!_tcsicmp(curr->getName(), name))
16d6f798
VK
778 {
779 object = curr;
5039dede 780 break;
16d6f798
VK
781 }
782 }
7c521895 783 unlockDciAccess();
16d6f798 784 return object;
5039dede
AK
785}
786
f05a8a45
VK
787/**
788 * Get item by it's description (case-insensetive)
789 */
abb85c62 790DCObject *Template::getDCObjectByDescription(const TCHAR *description)
5039dede 791{
16d6f798 792 DCObject *object = NULL;
5039dede 793
b06436f4 794 lockDciAccess(false);
5039dede 795 // Check if that item exists
16d6f798
VK
796 for(int i = 0; i < m_dcObjects->size(); i++)
797 {
798 DCObject *curr = m_dcObjects->get(i);
abb85c62 799 if (!_tcsicmp(curr->getDescription(), description))
16d6f798
VK
800 {
801 object = curr;
5039dede 802 break;
16d6f798
VK
803 }
804 }
805 unlockDciAccess();
806 return object;
5039dede
AK
807}
808
e7450f3b
VK
809/**
810 * Get item by GUID
811 */
812DCObject *Template::getDCObjectByGUID(const uuid& guid, bool lock)
813{
814 DCObject *object = NULL;
815
816 if (lock)
817 lockDciAccess(false);
818
819 // Check if that item exists
820 for(int i = 0; i < m_dcObjects->size(); i++)
821 {
822 DCObject *curr = m_dcObjects->get(i);
823 if (guid.equals(curr->getGuid()))
824 {
825 object = curr;
826 break;
827 }
828 }
829
830 if (lock)
831 unlockDciAccess();
832 return object;
833}
834
f05a8a45
VK
835/**
836 * Get item by it's index
837 */
16d6f798 838DCObject *Template::getDCObjectByIndex(int index)
5039dede 839{
b06436f4 840 lockDciAccess(false);
16d6f798 841 DCObject *object = m_dcObjects->get(index);
7c521895 842 unlockDciAccess();
16d6f798 843 return object;
5039dede
AK
844}
845
abb85c62
VK
846/**
847 * Get all DC objects with matching name and description
848 */
849NXSL_Value *Template::getAllDCObjectsForNXSL(const TCHAR *name, const TCHAR *description)
850{
851 NXSL_Array *list = new NXSL_Array();
852 lockDciAccess(false);
853 for(int i = 0; i < m_dcObjects->size(); i++)
854 {
855 DCObject *curr = m_dcObjects->get(i);
856 if (((name == NULL) || MatchString(name, curr->getName(), false)) &&
857 ((description == NULL) || MatchString(description, curr->getDescription(), false)))
858 {
4804be4e 859 list->set(list->size(), curr->createNXSLObject());
abb85c62
VK
860 }
861 }
862 unlockDciAccess();
863 return new NXSL_Value(list);
864}
865
f05a8a45
VK
866/**
867 * Redefined status calculation for template
868 */
27f9598d 869void Template::calculateCompoundStatus(BOOL bForcedRecalc)
5039dede 870{
db091a1f 871 m_status = STATUS_NORMAL;
5039dede
AK
872}
873
f05a8a45
VK
874/**
875 * Create NXCP message with object's data
876 */
8fe90adb 877void Template::fillMessageInternal(NXCPMessage *pMsg)
5039dede 878{
8fe90adb 879 NetObj::fillMessageInternal(pMsg);
b368969c
VK
880 pMsg->setField(VID_TEMPLATE_VERSION, m_dwVersion);
881 pMsg->setField(VID_FLAGS, m_flags);
882 pMsg->setField(VID_AUTOBIND_FILTER, CHECK_NULL_EX(m_applyFilterSource));
5039dede
AK
883}
884
f05a8a45
VK
885/**
886 * Modify object from NXCP message
887 */
8fe90adb 888UINT32 Template::modifyFromMessageInternal(NXCPMessage *pRequest)
5039dede 889{
5039dede 890 // Change template version
5c44534b 891 if (pRequest->isFieldExist(VID_TEMPLATE_VERSION))
b368969c 892 m_dwVersion = pRequest->getFieldAsUInt32(VID_TEMPLATE_VERSION);
5039dede 893
feab3324 894 // Change flags
5c44534b 895 if (pRequest->isFieldExist(VID_FLAGS))
b368969c 896 m_flags = pRequest->getFieldAsUInt32(VID_FLAGS);
feab3324 897
4d0c32f3 898 // Change apply filter
5c44534b 899 if (pRequest->isFieldExist(VID_AUTOBIND_FILTER))
4d0c32f3 900 {
4734707c 901 free(m_applyFilterSource);
feab3324 902 delete m_applyFilter;
b368969c 903 m_applyFilterSource = pRequest->getFieldAsString(VID_AUTOBIND_FILTER);
feab3324 904 if (m_applyFilterSource != NULL)
4d0c32f3 905 {
feab3324 906 TCHAR error[256];
4d0c32f3 907
9fc9ec2c 908 m_applyFilter = NXSLCompile(m_applyFilterSource, error, 256, NULL);
feab3324 909 if (m_applyFilter == NULL)
615621a4
VK
910 {
911 TCHAR buffer[1024];
912 _sntprintf(buffer, 1024, _T("Template::%s::%d"), m_name, m_id);
913 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, error, m_id);
c42b4551 914 nxlog_write(MSG_TEMPLATE_SCRIPT_COMPILATION_ERROR, EVENTLOG_WARNING_TYPE, "dss", m_id, m_name, error);
615621a4 915 }
4d0c32f3
VK
916 }
917 else
918 {
feab3324 919 m_applyFilter = NULL;
4d0c32f3
VK
920 }
921 }
4d0c32f3 922
8fe90adb 923 return NetObj::modifyFromMessageInternal(pRequest);
5039dede
AK
924}
925
6fd6de0a
VK
926/**
927 * Apply template to data collection target
928 */
929BOOL Template::applyToTarget(DataCollectionTarget *target)
5039dede 930{
967893bb 931 UINT32 *pdwItemList;
5039dede
AK
932 BOOL bErrors = FALSE;
933
934 // Link node to template
c42b4551 935 if (!isChild(target->getId()))
5039dede 936 {
1f8be1f4
VK
937 addChild(target);
938 target->addParent(this);
5039dede
AK
939 }
940
967893bb 941 pdwItemList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
6fd6de0a 942 DbgPrintf(2, _T("Apply %d items from template \"%s\" to target \"%s\""),
c42b4551 943 m_dcObjects->size(), m_name, target->getName());
5039dede
AK
944
945 // Copy items
16d6f798 946 for(int i = 0; i < m_dcObjects->size(); i++)
5039dede 947 {
16d6f798
VK
948 DCObject *object = m_dcObjects->get(i);
949 pdwItemList[i] = object->getId();
c42b4551 950 if (!target->applyTemplateItem(m_id, object))
5039dede
AK
951 {
952 bErrors = TRUE;
953 }
954 }
955
956 // Clean items deleted from template
c42b4551 957 target->cleanDeletedTemplateItems(m_id, m_dcObjects->size(), pdwItemList);
5039dede
AK
958
959 // Cleanup
960 free(pdwItemList);
961
96d97494
VK
962 target->onDataCollectionChange();
963
0c97b51c 964 // Queue update if target is a cluster
c42b4551 965 if (target->getObjectClass() == OBJECT_CLUSTER)
0c97b51c
VK
966 {
967 target->queueUpdate();
968 }
969
5039dede
AK
970 return bErrors;
971}
972
6fd6de0a
VK
973/**
974 * Queue template update
975 */
7c521895 976void Template::queueUpdate()
5039dede 977{
db091a1f
VK
978 lockChildList(false);
979 for(int i = 0; i < m_childList->size(); i++)
980 {
981 NetObj *object = m_childList->get(i);
982 if (object->isDataCollectionTarget())
5039dede 983 {
21c9acce 984 incRefCount();
d140955e
VK
985 TEMPLATE_UPDATE_INFO *pInfo = (TEMPLATE_UPDATE_INFO *)malloc(sizeof(TEMPLATE_UPDATE_INFO));
986 pInfo->updateType = APPLY_TEMPLATE;
5039dede 987 pInfo->pTemplate = this;
db091a1f 988 pInfo->targetId = object->getId();
d140955e 989 pInfo->removeDCI = false;
19dbc8ef 990 g_pTemplateUpdateQueue->put(pInfo);
5039dede 991 }
db091a1f
VK
992 }
993 unlockChildList();
5039dede
AK
994}
995
6fd6de0a
VK
996/**
997 * Queue template remove from node
998 */
d140955e 999void Template::queueRemoveFromTarget(UINT32 targetId, bool removeDCI)
5039dede 1000{
c42b4551 1001 lockProperties();
21c9acce 1002 incRefCount();
d140955e
VK
1003 TEMPLATE_UPDATE_INFO *pInfo = (TEMPLATE_UPDATE_INFO *)malloc(sizeof(TEMPLATE_UPDATE_INFO));
1004 pInfo->updateType = REMOVE_TEMPLATE;
5039dede 1005 pInfo->pTemplate = this;
6fd6de0a 1006 pInfo->targetId = targetId;
d140955e 1007 pInfo->removeDCI = removeDCI;
19dbc8ef 1008 g_pTemplateUpdateQueue->put(pInfo);
c42b4551 1009 unlockProperties();
5039dede
AK
1010}
1011
6fd6de0a
VK
1012/**
1013 * Get list of events used by DCIs
1014 */
967893bb 1015UINT32 *Template::getDCIEventsList(UINT32 *pdwCount)
5039dede 1016{
967893bb 1017 UINT32 i, j, *pdwList;
5039dede
AK
1018
1019 pdwList = NULL;
1020 *pdwCount = 0;
1021
b06436f4 1022 lockDciAccess(false);
967893bb 1023 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
5039dede 1024 {
16d6f798 1025 m_dcObjects->get(i)->getEventList(&pdwList, pdwCount);
5039dede 1026 }
7c521895 1027 unlockDciAccess();
5039dede
AK
1028
1029 // Clean list from duplicates
1030 for(i = 0; i < *pdwCount; i++)
1031 {
1032 for(j = i + 1; j < *pdwCount; j++)
1033 {
1034 if (pdwList[i] == pdwList[j])
1035 {
1036 (*pdwCount)--;
967893bb 1037 memmove(&pdwList[j], &pdwList[j + 1], sizeof(UINT32) * (*pdwCount - j));
5039dede
AK
1038 j--;
1039 }
1040 }
1041 }
1042
1043 return pdwList;
1044}
1045
25a1e9d0
VK
1046/**
1047 * Get list of scripts used by DCIs
1048 */
1049StringSet *Template::getDCIScriptList()
1050{
1051 StringSet *list = new StringSet;
1052
1053 lockDciAccess(false);
1054 for(int i = 0; i < m_dcObjects->size(); i++)
1055 {
1056 DCObject *o = m_dcObjects->get(i);
1057 if (o->getDataSource() == DS_SCRIPT)
1058 {
1059 const TCHAR *name = o->getName();
1060 const TCHAR *p = _tcschr(name, _T('('));
1061 if (p != NULL)
1062 {
1063 TCHAR buffer[256];
1064 nx_strncpy(buffer, name, p - name + 1);
1065 list->add(buffer);
1066 }
1067 else
1068 {
1069 list->add(name);
1070 }
1071 }
1072 }
1073 unlockDciAccess();
1074 return list;
1075}
1076
d51f2182
VK
1077/**
1078 * Create management pack record
1079 */
98ef8e4a 1080void Template::createExportRecord(String &str)
5039dede 1081{
25a1e9d0
VK
1082 TCHAR guid[48];
1083 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"),
de4af576 1084 m_id, m_guid.toString(guid), (const TCHAR *)EscapeStringForXML2(m_name), m_flags);
5039dede 1085
67de55fd
VK
1086 // Path in groups
1087 StringList path;
1088 ObjectArray<NetObj> *list = getParentList(OBJECT_TEMPLATEGROUP);
1089 TemplateGroup *parent = NULL;
1090 while(list->size() > 0)
1091 {
1092 parent = (TemplateGroup *)list->get(0);
1093 path.add(parent->getName());
1094 delete list;
1095 list = parent->getParentList(OBJECT_TEMPLATEGROUP);
1096 }
1097 delete list;
1098
1099 str.append(_T("\t\t\t<path>\n"));
1100 for(int j = path.size() - 1, id = 1; j >= 0; j--, id++)
1101 {
1102 str.append(_T("\t\t\t\t<element id=\""));
1103 str.append(id);
1104 str.append(_T("\">"));
1105 str.append(path.get(j));
1106 str.append(_T("</element>\n"));
1107 }
1108 str.append(_T("\t\t\t</path>\n\t\t\t<dataCollection>\n"));
1109
b06436f4 1110 lockDciAccess(false);
16d6f798 1111 for(int i = 0; i < m_dcObjects->size(); i++)
98ef8e4a 1112 m_dcObjects->get(i)->createExportRecord(str);
7c521895 1113 unlockDciAccess();
5039dede 1114
67de55fd 1115 str.append(_T("\t\t\t</dataCollection>\n"));
c42b4551 1116 lockProperties();
4d0c32f3
VK
1117 if (m_applyFilterSource != NULL)
1118 {
67de55fd 1119 str.append(_T("\t\t\t<filter>"));
4e0e77e6 1120 str.appendPreallocated(EscapeStringForXML(m_applyFilterSource, -1));
67de55fd 1121 str.append(_T("</filter>\n"));
4d0c32f3 1122 }
c42b4551 1123 unlockProperties();
67de55fd 1124 str.append(_T("\t\t</template>\n"));
5039dede
AK
1125}
1126
6fd6de0a
VK
1127/**
1128 * Enumerate all DCIs
1129 */
967893bb 1130bool Template::enumDCObjects(bool (* pfCallback)(DCObject *, UINT32, void *), void *pArg)
5039dede 1131{
16d6f798 1132 bool success = true;
5039dede 1133
b06436f4 1134 lockDciAccess(false);
16d6f798 1135 for(int i = 0; i < m_dcObjects->size(); i++)
5039dede 1136 {
16d6f798 1137 if (!pfCallback(m_dcObjects->get(i), i, pArg))
5039dede 1138 {
16d6f798 1139 success = false;
5039dede
AK
1140 break;
1141 }
1142 }
7c521895 1143 unlockDciAccess();
16d6f798 1144 return success;
5039dede
AK
1145}
1146
f05a8a45
VK
1147/**
1148 * (Re)associate all DCIs
1149 */
7c521895 1150void Template::associateItems()
5039dede 1151{
b06436f4 1152 lockDciAccess(false);
16d6f798
VK
1153 for(int i = 0; i < m_dcObjects->size(); i++)
1154 m_dcObjects->get(i)->changeBinding(0, this, FALSE);
7c521895 1155 unlockDciAccess();
5039dede
AK
1156}
1157
6fd6de0a
VK
1158/**
1159 * Prepare template for deletion
1160 */
22ee6d97 1161void Template::prepareForDeletion()
5039dede 1162{
c42b4551 1163 if (getObjectClass() == OBJECT_TEMPLATE)
5039dede 1164 {
db091a1f
VK
1165 lockChildList(false);
1166 for(int i = 0; i < m_childList->size(); i++)
5039dede 1167 {
db091a1f
VK
1168 NetObj *object = m_childList->get(i);
1169 if (object->isDataCollectionTarget())
1170 queueRemoveFromTarget(object->getId(), true);
5039dede 1171 }
db091a1f 1172 unlockChildList();
5039dede 1173 }
22ee6d97 1174 NetObj::prepareForDeletion();
5039dede 1175}
4d0c32f3 1176
171c2fd6
VK
1177/**
1178 * Check if template should be automatically applied to node
a84c073c
VK
1179 * Returns AutoBindDecision_Bind if applicable, AutoBindDecision_Unbind if not,
1180 * AutoBindDecision_Ignore if no change required (script error or no auto apply)
171c2fd6 1181 */
a84c073c 1182AutoBindDecision Template::isApplicable(Node *node)
4d0c32f3 1183{
a84c073c 1184 AutoBindDecision result = AutoBindDecision_Ignore;
4d0c32f3 1185
9fc9ec2c 1186 NXSL_VM *filter = NULL;
c42b4551 1187 lockProperties();
feab3324 1188 if ((m_flags & TF_AUTO_APPLY) && (m_applyFilter != NULL))
4d0c32f3 1189 {
3fadb0bb 1190 filter = new NXSL_VM(new NXSL_ServerEnv());
9fc9ec2c
VK
1191 if (!filter->load(m_applyFilter))
1192 {
7e32778c
VK
1193 TCHAR buffer[1024];
1194 _sntprintf(buffer, 1024, _T("Template::%s::%d"), m_name, m_id);
1195 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, filter->getErrorText(), m_id);
1196 nxlog_write(MSG_TEMPLATE_SCRIPT_EXECUTION_ERROR, EVENTLOG_WARNING_TYPE, "dss", m_id, m_name, filter->getErrorText());
9fc9ec2c
VK
1197 delete_and_null(filter);
1198 }
4d0c32f3 1199 }
9fc9ec2c
VK
1200 unlockProperties();
1201
1202 if (filter == NULL)
1203 return result;
1204
1205 filter->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, node)));
1206 if (filter->run())
1207 {
1208 NXSL_Value *value = filter->getResult();
1209 result = ((value != NULL) && (value->getValueAsInt32() != 0)) ? AutoBindDecision_Bind : AutoBindDecision_Unbind;
1210 }
1211 else
1212 {
1213 lockProperties();
1214 TCHAR buffer[1024];
1215 _sntprintf(buffer, 1024, _T("Template::%s::%d"), m_name, m_id);
1216 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, filter->getErrorText(), m_id);
1217 nxlog_write(MSG_TEMPLATE_SCRIPT_EXECUTION_ERROR, EVENTLOG_WARNING_TYPE, "dss", m_id, m_name, filter->getErrorText());
1218 unlockProperties();
1219 }
1220 delete filter;
4d0c32f3
VK
1221 return result;
1222}
5dbf115e
VK
1223
1224/**
4016c0df 1225 * Get last (current) DCI values. Moved to Template from DataCollectionTarget to allow
5dbf115e
VK
1226 * simplified creation of DCI selection dialog in management console. For classes not
1227 * derived from DataCollectionTarget actual values will always be empty strings
1228 * with data type DCI_DT_NULL.
1229 */
1fa2ca0e 1230UINT32 Template::getLastValues(NXCPMessage *msg, bool objectTooltipOnly, bool overviewOnly, bool includeNoValueObjects)
5dbf115e 1231{
b06436f4 1232 lockDciAccess(false);
5dbf115e 1233
967893bb 1234 UINT32 dwId = VID_DCI_VALUES_BASE, dwCount = 0;
5dbf115e
VK
1235 for(int i = 0; i < m_dcObjects->size(); i++)
1236 {
1237 DCObject *object = m_dcObjects->get(i);
a6312bd6 1238 if ((object->hasValue() || includeNoValueObjects) &&
1fa2ca0e
VK
1239 (!objectTooltipOnly || object->isShowOnObjectTooltip()) &&
1240 (!overviewOnly || object->isShowInObjectOverview()))
5dbf115e
VK
1241 {
1242 if (object->getType() == DCO_TYPE_ITEM)
1243 {
4a435beb 1244 ((DCItem *)object)->fillLastValueMessage(msg, dwId);
5dbf115e
VK
1245 dwId += 50;
1246 dwCount++;
1247 }
1248 else if (object->getType() == DCO_TYPE_TABLE)
1249 {
4a435beb 1250 ((DCTable *)object)->fillLastValueSummaryMessage(msg, dwId);
5dbf115e
VK
1251 dwId += 50;
1252 dwCount++;
1253 }
1254 }
1255 }
b368969c 1256 msg->setField(VID_NUM_ITEMS, dwCount);
5dbf115e
VK
1257
1258 unlockDciAccess();
1259 return RCC_SUCCESS;
1260}
9fd816cc
VK
1261
1262/**
1263 * Called when data collection configuration changed
1264 */
1265void Template::onDataCollectionChange()
1266{
9cac1330
VK
1267 // Do not queue updates for subclasses
1268 if (getObjectClass() == OBJECT_TEMPLATE)
1269 queueUpdate();
9fd816cc 1270}
98ef8e4a
VK
1271
1272/**
1273 * Update template from import
1274 */
1275void Template::updateFromImport(ConfigEntry *config)
1276{
1277 // Name and version
e7450f3b 1278 lockProperties();
98ef8e4a
VK
1279 m_dwVersion = config->getSubEntryValueAsUInt(_T("version"), 0, m_dwVersion);
1280 m_flags = config->getSubEntryValueAsUInt(_T("flags"), 0, m_flags);
e7450f3b 1281 unlockProperties();
98ef8e4a
VK
1282
1283 // Auto-apply filter
e7450f3b 1284 setAutoApplyFilter(config->getSubEntryValue(_T("filter")));
98ef8e4a 1285
98ef8e4a 1286 // Data collection
e7450f3b
VK
1287 ObjectArray<uuid> guidList(32, 32, true);
1288
1289 lockDciAccess(true);
98ef8e4a
VK
1290 ConfigEntry *dcRoot = config->findEntry(_T("dataCollection"));
1291 if (dcRoot != NULL)
1292 {
1293 ObjectArray<ConfigEntry> *dcis = dcRoot->getSubEntries(_T("dci#*"));
1294 for(int i = 0; i < dcis->size(); i++)
1295 {
e7450f3b
VK
1296 ConfigEntry *e = dcis->get(i);
1297 uuid guid = e->getSubEntryValueAsUUID(_T("guid"));
1298 DCObject *curr = !guid.isNull() ? getDCObjectByGUID(guid, false) : NULL;
1299 if ((curr != NULL) && (curr->getType() == DCO_TYPE_ITEM))
1300 {
1301 curr->updateFromImport(e);
1302 }
1303 else
1304 {
1305 m_dcObjects->add(new DCItem(e, this));
1306 }
1307 guidList.add(new uuid(guid));
98ef8e4a
VK
1308 }
1309 delete dcis;
1310
1311 ObjectArray<ConfigEntry> *dctables = dcRoot->getSubEntries(_T("dctable#*"));
1312 for(int i = 0; i < dctables->size(); i++)
1313 {
e7450f3b
VK
1314 ConfigEntry *e = dctables->get(i);
1315 uuid guid = e->getSubEntryValueAsUUID(_T("guid"));
1316 DCObject *curr = !guid.isNull() ? getDCObjectByGUID(guid, false) : NULL;
1317 if ((curr != NULL) && (curr->getType() == DCO_TYPE_TABLE))
1318 {
1319 curr->updateFromImport(e);
1320 }
1321 else
1322 {
1323 m_dcObjects->add(new DCTable(e, this));
1324 }
1325 guidList.add(new uuid(guid));
98ef8e4a
VK
1326 }
1327 delete dctables;
1328 }
e7450f3b
VK
1329
1330 // Delete DCIs missing in import
1331 IntegerArray<UINT32> deleteList;
1332 for(int i = 0; i < m_dcObjects->size(); i++)
1333 {
1334 bool found = false;
1335 for(int j = 0; j < guidList.size(); j++)
1336 {
1337 if (guidList.get(j)->equals(m_dcObjects->get(i)->getGuid()))
1338 {
1339 found = true;
1340 break;
1341 }
1342 }
1343
1344 if (!found)
1345 {
1346 deleteList.add(m_dcObjects->get(i)->getId());
1347 }
1348 }
1349
1350 for(int i = 0; i < deleteList.size(); i++)
1351 deleteDCObject(deleteList.get(i), false);
1352
1353 unlockDciAccess();
1354
1355 queueUpdate();
98ef8e4a 1356}