getters for message classes
[public/netxms.git] / src / server / core / condition.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
22aa5156 3** Copyright (C) 2003-2011 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: container.cpp
20**
21**/
22
23#include "nxcore.h"
24
21c9acce
VK
25/**
26 * Default constructor
27 */
28Condition::Condition() : NetObj()
5039dede
AK
29{
30 m_pszScript = NULL;
31 m_pDCIList = NULL;
32 m_dwDCICount = 0;
33 m_pszScript = 0;
34 m_dwSourceObject = 0;
35 m_nActiveStatus = STATUS_MAJOR;
36 m_nInactiveStatus = STATUS_NORMAL;
37 m_pCompiledScript = NULL;
38 m_bIsActive = FALSE;
39 m_tmLastPoll = 0;
40 m_bQueuedForPolling = FALSE;
41 m_dwActivationEventCode = EVENT_CONDITION_ACTIVATED;
42 m_dwDeactivationEventCode = EVENT_CONDITION_DEACTIVATED;
43}
44
21c9acce
VK
45/**
46 * Constructor for new objects
47 */
01152a54 48Condition::Condition(bool hidden) : NetObj()
5039dede
AK
49{
50 m_pszScript = NULL;
51 m_pDCIList = NULL;
52 m_dwDCICount = 0;
53 m_pszScript = 0;
54 m_dwSourceObject = 0;
55 m_nActiveStatus = STATUS_MAJOR;
56 m_nInactiveStatus = STATUS_NORMAL;
01152a54 57 m_isHidden = hidden;
5039dede
AK
58 m_pCompiledScript = NULL;
59 m_bIsActive = FALSE;
60 m_tmLastPoll = 0;
61 m_bQueuedForPolling = FALSE;
62 m_dwActivationEventCode = EVENT_CONDITION_ACTIVATED;
63 m_dwDeactivationEventCode = EVENT_CONDITION_DEACTIVATED;
64}
65
66
67//
68// Destructor
69//
70
71Condition::~Condition()
72{
73 safe_free(m_pDCIList);
74 safe_free(m_pszScript);
75 delete m_pCompiledScript;
76}
77
78
79//
80// Load object from database
81//
82
967893bb 83BOOL Condition::CreateFromDB(UINT32 dwId)
5039dede
AK
84{
85 TCHAR szQuery[512];
86 DB_RESULT hResult;
967893bb 87 UINT32 i;
5039dede
AK
88
89 m_dwId = dwId;
90
89135050 91 if (!loadCommonProperties())
5039dede
AK
92 return FALSE;
93
94 // Load properties
95 _sntprintf(szQuery, 512, _T("SELECT activation_event,deactivation_event,")
96 _T("source_object,active_status,inactive_status,")
97 _T("script FROM conditions WHERE id=%d"), dwId);
98 hResult = DBSelect(g_hCoreDB, szQuery);
99 if (hResult == NULL)
100 return FALSE; // Query failed
101
102 if (DBGetNumRows(hResult) == 0)
103 {
104 // No object with given ID in database
105 DBFreeResult(hResult);
106 return FALSE;
107 }
108
109 m_dwActivationEventCode = DBGetFieldULong(hResult, 0, 0);
110 m_dwDeactivationEventCode = DBGetFieldULong(hResult, 0, 1);
111 m_dwSourceObject = DBGetFieldULong(hResult, 0, 2);
112 m_nActiveStatus = DBGetFieldLong(hResult, 0, 3);
113 m_nInactiveStatus = DBGetFieldLong(hResult, 0, 4);
114 m_pszScript = DBGetField(hResult, 0, 5, NULL, 0);
115 DecodeSQLString(m_pszScript);
116
117 DBFreeResult(hResult);
118
119 // Compile script
120 m_pCompiledScript = (NXSL_Program *)NXSLCompile(m_pszScript, szQuery, 512);
121 if (m_pCompiledScript == NULL)
122 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE,
123 "dss", m_dwId, m_szName, szQuery);
124
125 // Load DCI map
126 _sntprintf(szQuery, 512, _T("SELECT dci_id,node_id,dci_func,num_polls ")
127 _T("FROM cond_dci_map WHERE condition_id=%d ORDER BY sequence_number"), dwId);
128 hResult = DBSelect(g_hCoreDB, szQuery);
129 if (hResult == NULL)
130 return FALSE; // Query failed
131
132 m_dwDCICount = DBGetNumRows(hResult);
133 if (m_dwDCICount > 0)
134 {
135 m_pDCIList = (INPUT_DCI *)malloc(sizeof(INPUT_DCI) * m_dwDCICount);
136 for(i = 0; i < m_dwDCICount; i++)
137 {
138 m_pDCIList[i].dwId = DBGetFieldULong(hResult, i, 0);
139 m_pDCIList[i].dwNodeId = DBGetFieldULong(hResult, i, 1);
140 m_pDCIList[i].nFunction = DBGetFieldLong(hResult, i, 2);
141 m_pDCIList[i].nPolls = DBGetFieldLong(hResult, i, 3);
142 }
143 }
144 DBFreeResult(hResult);
145
89135050 146 return loadACLFromDB();
5039dede
AK
147}
148
149
150//
151// Save object to database
152//
153
154BOOL Condition::SaveToDB(DB_HANDLE hdb)
155{
156 TCHAR *pszEscScript, *pszQuery;
157 DB_RESULT hResult;
158 BOOL bNewObject = TRUE;
967893bb 159 UINT32 i;
5039dede
AK
160
161 LockData();
162
89135050 163 saveCommonProperties(hdb);
5039dede
AK
164
165 pszEscScript = EncodeSQLString(CHECK_NULL_EX(m_pszScript));
35f836fe
VK
166 size_t qlen = _tcslen(pszEscScript) + 1024;
167 pszQuery = (TCHAR *)malloc(sizeof(TCHAR) * qlen);
5039dede
AK
168
169 // Check for object's existence in database
35f836fe 170 _sntprintf(pszQuery, qlen, _T("SELECT id FROM conditions WHERE id=%d"), m_dwId);
5039dede
AK
171 hResult = DBSelect(hdb, pszQuery);
172 if (hResult != NULL)
173 {
174 if (DBGetNumRows(hResult) > 0)
175 bNewObject = FALSE;
176 DBFreeResult(hResult);
177 }
178
179 // Form and execute INSERT or UPDATE query
180 if (bNewObject)
181 {
35f836fe
VK
182 _sntprintf(pszQuery, qlen,
183 _T("INSERT INTO conditions (id,activation_event,")
5039dede
AK
184 _T("deactivation_event,source_object,active_status,")
185 _T("inactive_status,script) VALUES (%d,%d,%d,%d,%d,%d,'%s')"),
186 m_dwId, m_dwActivationEventCode, m_dwDeactivationEventCode,
187 m_dwSourceObject, m_nActiveStatus, m_nInactiveStatus, pszEscScript);
188 }
189 else
190 {
35f836fe
VK
191 _sntprintf(pszQuery, qlen,
192 _T("UPDATE conditions SET activation_event=%d,")
5039dede
AK
193 _T("deactivation_event=%d,source_object=%d,active_status=%d,")
194 _T("inactive_status=%d,script='%s' WHERE id=%d"),
195 m_dwActivationEventCode, m_dwDeactivationEventCode, m_dwSourceObject,
196 m_nActiveStatus, m_nInactiveStatus, pszEscScript, m_dwId);
197 }
198 free(pszEscScript);
199 DBQuery(hdb, pszQuery);
200
201 // Save DCI mapping
35f836fe 202 _sntprintf(pszQuery, qlen, _T("DELETE FROM cond_dci_map WHERE condition_id=%d"), m_dwId);
5039dede
AK
203 DBQuery(hdb, pszQuery);
204 for(i = 0; i < m_dwDCICount; i++)
205 {
35f836fe
VK
206 _sntprintf(pszQuery, qlen, _T("INSERT INTO cond_dci_map (condition_id,sequence_number,dci_id,node_id,")
207 _T("dci_func,num_polls) VALUES (%d,%d,%d,%d,%d,%d)"),
5039dede
AK
208 m_dwId, i, m_pDCIList[i].dwId, m_pDCIList[i].dwNodeId,
209 m_pDCIList[i].nFunction, m_pDCIList[i].nPolls);
210 DBQuery(hdb, pszQuery);
211 }
212 free(pszQuery);
213
214 // Save access list
89135050 215 saveACLToDB(hdb);
5039dede
AK
216
217 // Unlock object and clear modification flag
01152a54 218 m_isModified = false;
5039dede
AK
219 UnlockData();
220 return TRUE;
221}
222
22ee6d97
VK
223/**
224 * Delete object from database
225 */
226bool Condition::deleteFromDB(DB_HANDLE hdb)
5039dede 227{
22ee6d97
VK
228 bool success = NetObj::deleteFromDB(hdb);
229 if (success)
230 success = executeQueryOnObject(hdb, _T("DELETE FROM conditions WHERE id=?"));
231 if (success)
232 success = executeQueryOnObject(hdb, _T("DELETE FROM cond_dci_map WHERE condition_id=?"));
233 return success;
5039dede
AK
234}
235
22ee6d97
VK
236/**
237 * Create NXCP message from object
238 */
5039dede
AK
239void Condition::CreateMessage(CSCPMessage *pMsg)
240{
967893bb 241 UINT32 i, dwId;
5039dede
AK
242
243 NetObj::CreateMessage(pMsg);
244 pMsg->SetVariable(VID_SCRIPT, CHECK_NULL_EX(m_pszScript));
245 pMsg->SetVariable(VID_ACTIVATION_EVENT, m_dwActivationEventCode);
246 pMsg->SetVariable(VID_DEACTIVATION_EVENT, m_dwDeactivationEventCode);
247 pMsg->SetVariable(VID_SOURCE_OBJECT, m_dwSourceObject);
248 pMsg->SetVariable(VID_ACTIVE_STATUS, (WORD)m_nActiveStatus);
249 pMsg->SetVariable(VID_INACTIVE_STATUS, (WORD)m_nInactiveStatus);
250 pMsg->SetVariable(VID_NUM_ITEMS, m_dwDCICount);
251 for(i = 0, dwId = VID_DCI_LIST_BASE; (i < m_dwDCICount) && (dwId < (VID_DCI_LIST_LAST + 1)); i++)
252 {
253 pMsg->SetVariable(dwId++, m_pDCIList[i].dwId);
254 pMsg->SetVariable(dwId++, m_pDCIList[i].dwNodeId);
255 pMsg->SetVariable(dwId++, (WORD)m_pDCIList[i].nFunction);
256 pMsg->SetVariable(dwId++, (WORD)m_pDCIList[i].nPolls);
257 dwId += 6;
258 }
259}
260
261
262//
263// Modify object from NXCP message
264//
265
967893bb 266UINT32 Condition::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
5039dede 267{
967893bb 268 UINT32 i, dwId;
5039dede 269 NetObj *pObject;
5039dede
AK
270
271 if (!bAlreadyLocked)
272 LockData();
273
274 // Change script
275 if (pRequest->IsVariableExist(VID_SCRIPT))
276 {
277 TCHAR szError[1024];
278
279 safe_free(m_pszScript);
280 delete m_pCompiledScript;
281 m_pszScript = pRequest->GetVariableStr(VID_SCRIPT);
282 m_pCompiledScript = (NXSL_Program *)NXSLCompile(m_pszScript, szError, 1024);
283 if (m_pCompiledScript == NULL)
284 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE,
285 "dss", m_dwId, m_szName, szError);
286 }
287
288 // Change activation event
289 if (pRequest->IsVariableExist(VID_ACTIVATION_EVENT))
290 m_dwActivationEventCode = pRequest->GetVariableLong(VID_ACTIVATION_EVENT);
291
292 // Change deactivation event
293 if (pRequest->IsVariableExist(VID_DEACTIVATION_EVENT))
294 m_dwDeactivationEventCode = pRequest->GetVariableLong(VID_DEACTIVATION_EVENT);
295
296 // Change source object
297 if (pRequest->IsVariableExist(VID_SOURCE_OBJECT))
298 m_dwSourceObject = pRequest->GetVariableLong(VID_SOURCE_OBJECT);
299
300 // Change active status
301 if (pRequest->IsVariableExist(VID_ACTIVE_STATUS))
302 m_nActiveStatus = pRequest->GetVariableShort(VID_ACTIVE_STATUS);
303
304 // Change inactive status
305 if (pRequest->IsVariableExist(VID_INACTIVE_STATUS))
306 m_nInactiveStatus = pRequest->GetVariableShort(VID_INACTIVE_STATUS);
307
308 // Change DCI list
309 if (pRequest->IsVariableExist(VID_NUM_ITEMS))
310 {
311 safe_free(m_pDCIList);
312 m_dwDCICount = pRequest->GetVariableLong(VID_NUM_ITEMS);
313 if (m_dwDCICount > 0)
314 {
315 m_pDCIList = (INPUT_DCI *)malloc(sizeof(INPUT_DCI) * m_dwDCICount);
316 for(i = 0, dwId = VID_DCI_LIST_BASE; (i < m_dwDCICount) && (dwId < (VID_DCI_LIST_LAST + 1)); i++)
317 {
318 m_pDCIList[i].dwId = pRequest->GetVariableLong(dwId++);
319 m_pDCIList[i].dwNodeId = pRequest->GetVariableLong(dwId++);
320 m_pDCIList[i].nFunction = pRequest->GetVariableShort(dwId++);
321 m_pDCIList[i].nPolls = pRequest->GetVariableShort(dwId++);
322 dwId += 6;
323 }
324
325 // Update cache size of DCIs
326 for(i = 0; i < m_dwDCICount; i++)
327 {
328 pObject = FindObjectById(m_pDCIList[i].dwNodeId);
329 if (pObject != NULL)
330 {
331 if (pObject->Type() == OBJECT_NODE)
332 {
16d6f798
VK
333 DCObject *pItem = ((Node *)pObject)->getDCObjectById(m_pDCIList[i].dwId);
334 if ((pItem != NULL) && (pItem->getType() == DCO_TYPE_ITEM))
5039dede 335 {
16d6f798 336 ((DCItem *)pItem)->updateCacheSize(m_dwId);
5039dede
AK
337 }
338 }
339 }
340 }
341 }
342 else
343 {
344 m_pDCIList = NULL;
345 }
346 }
347
348 return NetObj::ModifyFromMessage(pRequest, TRUE);
349}
350
21c9acce
VK
351/**
352 * Lock for polling
353 */
d5e8ff90 354void Condition::LockForPoll()
5039dede 355{
21c9acce 356 incRefCount();
5039dede
AK
357 m_bQueuedForPolling = TRUE;
358}
359
21c9acce
VK
360/**
361 * This method should be called by poller thread when poll finish
362 */
d5e8ff90 363void Condition::EndPoll()
5039dede
AK
364{
365 LockData();
366 m_bQueuedForPolling = FALSE;
367 m_tmLastPoll = time(NULL);
368 UnlockData();
21c9acce 369 decRefCount();
5039dede
AK
370}
371
21c9acce
VK
372/**
373 * Check condition
374 */
3f7c0fe4 375void Condition::check()
5039dede
AK
376{
377 NXSL_ServerEnv *pEnv;
378 NXSL_Value **ppValueList, *pValue;
379 NetObj *pObject;
967893bb 380 UINT32 i, dwNumValues;
5039dede
AK
381 int iOldStatus = m_iStatus;
382
383 if ((m_pCompiledScript == NULL) || (m_iStatus == STATUS_UNMANAGED))
384 return;
385
386 pEnv = new NXSL_ServerEnv;
387
388 LockData();
389 ppValueList = (NXSL_Value **)malloc(sizeof(NXSL_Value *) * m_dwDCICount);
390 memset(ppValueList, 0, sizeof(NXSL_Value *) * m_dwDCICount);
391 for(i = 0; i < m_dwDCICount; i++)
392 {
393 pObject = FindObjectById(m_pDCIList[i].dwNodeId);
394 if (pObject != NULL)
395 {
396 if (pObject->Type() == OBJECT_NODE)
397 {
16d6f798
VK
398 DCObject *pItem = ((Node *)pObject)->getDCObjectById(m_pDCIList[i].dwId);
399 if ((pItem != NULL) && (pItem->getType() == DCO_TYPE_ITEM))
5039dede 400 {
16d6f798 401 ppValueList[i] = ((DCItem *)pItem)->getValueForNXSL(m_pDCIList[i].nFunction, m_pDCIList[i].nPolls);
5039dede
AK
402 }
403 }
404 }
405 if (ppValueList[i] == NULL)
406 ppValueList[i] = new NXSL_Value;
407 }
408 dwNumValues = m_dwDCICount;
409 UnlockData();
410
22aa5156
VK
411 // Create array from values
412 NXSL_Array *array = new NXSL_Array;
413 for(i = 0; i < dwNumValues; i++)
414 {
415 array->set(i + 1, new NXSL_Value(ppValueList[i]));
416 }
417 m_pCompiledScript->setGlobalVariable(_T("$values"), new NXSL_Value(array));
418
5039dede
AK
419 DbgPrintf(6, _T("Running evaluation script for condition %d \"%s\""),
420 m_dwId, m_szName);
bb5365ed 421 if (m_pCompiledScript->run(pEnv, dwNumValues, ppValueList) == 0)
5039dede 422 {
bb5365ed
VK
423 pValue = m_pCompiledScript->getResult();
424 if (pValue->getValueAsInt32() == 0)
5039dede
AK
425 {
426 if (m_bIsActive)
427 {
428 // Deactivate condition
429 LockData();
430 m_iStatus = m_nInactiveStatus;
431 m_bIsActive = FALSE;
432 Modify();
433 UnlockData();
434
435 PostEvent(m_dwDeactivationEventCode,
436 (m_dwSourceObject == 0) ? g_dwMgmtNode : m_dwSourceObject,
437 "dsdd", m_dwId, m_szName, iOldStatus, m_iStatus);
438
439 DbgPrintf(6, _T("Condition %d \"%s\" deactivated"),
440 m_dwId, m_szName);
441 }
442 else
443 {
444 DbgPrintf(6, _T("Condition %d \"%s\" still inactive"),
445 m_dwId, m_szName);
446 LockData();
447 if (m_iStatus != m_nInactiveStatus)
448 {
449 m_iStatus = m_nInactiveStatus;
450 Modify();
451 }
452 UnlockData();
453 }
454 }
455 else
456 {
457 if (!m_bIsActive)
458 {
459 // Activate condition
460 LockData();
461 m_iStatus = m_nActiveStatus;
462 m_bIsActive = TRUE;
463 Modify();
464 UnlockData();
465
466 PostEvent(m_dwActivationEventCode,
467 (m_dwSourceObject == 0) ? g_dwMgmtNode : m_dwSourceObject,
468 "dsdd", m_dwId, m_szName, iOldStatus, m_iStatus);
469
470 DbgPrintf(6, _T("Condition %d \"%s\" activated"),
471 m_dwId, m_szName);
472 }
473 else
474 {
475 DbgPrintf(6, _T("Condition %d \"%s\" still active"),
476 m_dwId, m_szName);
477 LockData();
478 if (m_iStatus != m_nActiveStatus)
479 {
480 m_iStatus = m_nActiveStatus;
481 Modify();
482 }
483 UnlockData();
484 }
485 }
486 }
487 else
488 {
489 nxlog_write(MSG_COND_SCRIPT_EXECUTION_ERROR, EVENTLOG_ERROR_TYPE,
bb5365ed 490 "dss", m_dwId, m_szName, m_pCompiledScript->getErrorText());
5039dede
AK
491
492 LockData();
493 if (m_iStatus != STATUS_UNKNOWN)
494 {
495 m_iStatus = STATUS_UNKNOWN;
496 Modify();
497 }
498 UnlockData();
499 }
500 free(ppValueList);
501
502 // Cause parent object(s) to recalculate it's status
503 if (iOldStatus != m_iStatus)
504 {
505 LockParentList(FALSE);
506 for(i = 0; i < m_dwParentCount; i++)
27f9598d 507 m_pParentList[i]->calculateCompoundStatus();
5039dede
AK
508 UnlockParentList();
509 }
510}
511
512
513//
514// Determine DCI cache size required by condition object
515//
516
967893bb 517int Condition::getCacheSizeForDCI(UINT32 dwItemId, BOOL bNoLock)
5039dede 518{
967893bb 519 UINT32 i;
5039dede
AK
520 int nSize = 0;
521
522 if (!bNoLock)
523 LockData();
524 for(i = 0; i < m_dwDCICount; i++)
525 {
526 if (m_pDCIList[i].dwId == dwItemId)
527 {
528 switch(m_pDCIList[i].nFunction)
529 {
530 case F_LAST:
531 nSize = 1;
532 break;
533 case F_DIFF:
534 nSize = 2;
535 break;
536 default:
537 nSize = m_pDCIList[i].nPolls;
538 break;
539 }
540 break;
541 }
542 }
543 if (!bNoLock)
544 UnlockData();
545 return nSize;
546}