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