preparation for tabular DCI support: code refactoring, list of supported tables cache...
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 18 Mar 2012 17:17:15 +0000 (17:17 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 18 Mar 2012 17:17:15 +0000 (17:17 +0000)
23 files changed:
include/netxmsdb.h
include/nms_agent.h
include/nms_common.h
include/nms_util.h
include/nxclapi.h
sql/schema.in
src/agent/core/getparam.cpp
src/agent/subagents/winnt/main.cpp
src/server/core/cluster.cpp
src/server/core/datacoll.cpp
src/server/core/dcitem.cpp
src/server/core/dcobject.cpp [new file with mode: 0644]
src/server/core/id.cpp
src/server/core/node.cpp
src/server/core/nxcore.vcproj
src/server/core/session.cpp
src/server/include/nms_dcoll.h
src/server/include/nms_objects.h
src/server/include/nxsrvapi.h
src/server/libnxsrv/agent.cpp
src/server/tools/nxdbmgr/upgrade.cpp
src/server/tools/nxget/nxget.cpp
tools/chkmsgs.sh [new file with mode: 0755]

index 9e0cbec..41f112f 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** NetXMS - Network Management System
-** Copyright (C) 2003-2011 Victor Kirhenshtein
+** Copyright (C) 2003-2012 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
@@ -23,6 +23,6 @@
 #ifndef _netxmsdb_h
 #define _netxmsdb_h
 
-#define DB_FORMAT_VERSION   247
+#define DB_FORMAT_VERSION   248
 
 #endif
index 7917f58..a357ec1 100644 (file)
 #define DCIDESC_DEPRECATED                        _T("<deprecated>")
 
 
+#define DCTDESC_SYSTEM_PROCESSES                  _T("List of all processes in a system")
+
+
 //
 // Subagent's parameter information
 //
@@ -365,6 +368,8 @@ typedef struct
    TCHAR name[MAX_PARAM_NAME];
    LONG (* handler)(const TCHAR *, const TCHAR *, Table *);
    const TCHAR *arg;
+       TCHAR instanceColumn[MAX_COLUMN_NAME];
+   TCHAR description[MAX_DB_STRING];
 } NETXMS_SUBAGENT_TABLE;
 
 
index 7020275..45852b1 100644 (file)
 #define MAX_SECRET_LENGTH        64
 #define MAX_DB_STRING            256
 #define MAX_PARAM_NAME           256
+#define MAX_COLUMN_NAME          64
 #define MAX_DNS_NAME             256
 #define GROUP_FLAG               ((DWORD)0x80000000)
 
index 50a7935..edd1211 100644 (file)
@@ -424,6 +424,25 @@ public:
 };
 
 
+//
+// Auxilliary class to hold dynamically allocated array of structures
+//
+
+template <class T> class StructArray
+{
+private:
+       int m_count;
+       T *m_data;
+
+public:
+       StructArray(T *data, int count) { m_data = data; m_count = count; }
+       ~StructArray() { safe_free(m_data); }
+
+       int size() { return m_count; }
+       T *get(int index) { return ((index >= 0) && (index < m_count)) ? &m_data[index] : NULL; }
+};
+
+
 //
 // Auxilliary class for objects which counts references and
 // destroys itself wheren reference count falls to 0
index cd6a505..de5033c 100644 (file)
@@ -898,6 +898,18 @@ typedef struct
 } NXC_AGENT_PARAM;
 
 
+//
+// Agent's table information
+//
+
+typedef struct
+{
+   TCHAR name[MAX_PARAM_NAME];
+   TCHAR instanceColumn[MAX_COLUMN_NAME];
+   TCHAR description[MAX_DB_STRING];
+} NXC_AGENT_TABLE;
+
+
 //
 // Action structure
 //
index 9130e0b..708fd50 100644 (file)
@@ -545,11 +545,53 @@ CREATE TABLE items
        base_units integer not null,            // bytes, seconds, etc.
        unit_multiplier integer not null,       // kilo, mega, milli, etc.
        custom_units_name varchar(63),  // units name of base_units = CUSTOM
-       perftab_settings SQL_TEXT,                      // Settings for dispklaying graph on performance tab
+       perftab_settings SQL_TEXT,                      // Settings for displaying graph on performance tab
        PRIMARY KEY(item_id)
 ) TABLE_TYPE;
 
 
+/*
+** Data collection tables
+*/
+
+CREATE TABLE dc_tables
+(
+       item_id integer not null,
+       node_id integer not null,       
+       template_id integer not null,
+       template_item_id integer not null,
+       name varchar(255) null,
+       instance_column varchar(63) null,
+       description varchar(255) null,
+       flags integer not null,
+       source integer not null,        // 0 for internal or 1 for native agent or 2 for SNMP
+       snmp_port integer not null,
+       polling_interval integer not null,
+       retention_time integer not null,
+       status integer not null,                        // ACTIVE, DISABLED or NOT_SUPPORTED
+       system_tag varchar(255) null,                   // System tag
+       resource_id integer not null,   // associated cluster resource ID
+       proxy_node integer not null,    // ID of proxy node (for SNMP and agent items)
+       perftab_settings SQL_TEXT,                      // Settings for displaying graph on performance tab
+       PRIMARY KEY(item_id)
+) TABLE_TYPE;
+
+
+/*
+** Columns for data collection tables
+*/
+
+CREATE TABLE dc_table_columns
+(
+       table_id integer not null,
+       column_name varchar(63) not null,
+       snmp_oid varchar(1023) null,            // SNMP OID for this column, valid only for SNMP tables
+       data_type integer not null,
+       transformation_script SQL_TEXT null,
+       PRIMARY KEY(table_id,column_name)
+) TABLE_TYPE;
+
+
 /*
 ** Schedules for DCIs
 */
index bca8532..3d74388 100644 (file)
@@ -686,5 +686,7 @@ void GetParameterList(CSCPMessage *pMsg)
    for(i = 0, dwId = VID_TABLE_LIST_BASE; i < m_iNumTables; i++)
    {
       pMsg->SetVariable(dwId++, m_pTableList[i].name);
+               pMsg->SetVariable(dwId++, m_pTableList[i].instanceColumn);
+               pMsg->SetVariable(dwId++, m_pTableList[i].description);
    }
 }
index 3645e44..1ceb0f8 100644 (file)
@@ -150,7 +150,7 @@ static NETXMS_SUBAGENT_LIST m_enums[] =
 };
 static NETXMS_SUBAGENT_TABLE m_tables[] =
 {
-       { "System.Processes", H_ProcessTable, NULL }
+       { "System.Processes", H_ProcessTable, NULL, "PID", DCTDESC_SYSTEM_PROCESSES }
 };
 static NETXMS_SUBAGENT_ACTION m_actions[] =
 {
index b87c2d8..2a465a5 100644 (file)
@@ -479,17 +479,17 @@ void Cluster::calculateCompoundStatus(BOOL bForcedRecalc)
 // Check if given address is within sync network
 //
 
-BOOL Cluster::isSyncAddr(DWORD dwAddr)
+bool Cluster::isSyncAddr(DWORD dwAddr)
 {
        DWORD i;
-       BOOL bRet = FALSE;
+       bool bRet = false;
 
        LockData();
        for(i = 0; i < m_dwNumSyncNets; i++)
        {
                if ((dwAddr & m_pSyncNetList[i].dwMask) == m_pSyncNetList[i].dwAddr)
                {
-                       bRet = TRUE;
+                       bRet = true;
                        break;
                }
        }
@@ -502,17 +502,17 @@ BOOL Cluster::isSyncAddr(DWORD dwAddr)
 // Check if given address is a resource address
 //
 
-BOOL Cluster::isVirtualAddr(DWORD dwAddr)
+bool Cluster::isVirtualAddr(DWORD dwAddr)
 {
        DWORD i;
-       BOOL bRet = FALSE;
+       bool bRet = false;
 
        LockData();
        for(i = 0; i < m_dwNumResources; i++)
        {
                if (m_pResourceList[i].dwIpAddr == dwAddr)
                {
-                       bRet = TRUE;
+                       bRet = true;
                        break;
                }
        }
@@ -676,9 +676,9 @@ void Cluster::statusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller)
 // Check if node is current owner of resource
 //
 
-BOOL Cluster::isResourceOnNode(DWORD dwResource, DWORD dwNode)
+bool Cluster::isResourceOnNode(DWORD dwResource, DWORD dwNode)
 {
-       BOOL bRet = FALSE;
+       bool bRet = FALSE;
        DWORD i;
 
        LockData();
@@ -687,7 +687,7 @@ BOOL Cluster::isResourceOnNode(DWORD dwResource, DWORD dwNode)
                if (m_pResourceList[i].dwId == dwResource)
                {
                        if (m_pResourceList[i].dwCurrOwner == dwNode)
-                               bRet = TRUE;
+                               bRet = true;
                        break;
                }
        }
index 98b7224..9bbb480 100644 (file)
@@ -335,24 +335,23 @@ static void UpdateParamList(NetObj *object, void *data)
 {
        struct __param_list *fullList = (struct __param_list *)data;
 
-       NXC_AGENT_PARAM *paramList;
-       DWORD numParams;
-       ((Node *)object)->openParamList(&numParams, &paramList);
-       if ((numParams > 0) && (paramList != NULL))
+       StructArray<NXC_AGENT_PARAM> *paramList;
+       ((Node *)object)->openParamList(&paramList);
+       if ((paramList != NULL) && (paramList->size() > 0))
        {
-               fullList->data = (NXC_AGENT_PARAM *)realloc(fullList->data, sizeof(NXC_AGENT_PARAM) * (fullList->size + numParams));
-               for(DWORD i = 0; i < numParams; i++)
+               fullList->data = (NXC_AGENT_PARAM *)realloc(fullList->data, sizeof(NXC_AGENT_PARAM) * (fullList->size + paramList->size()));
+               for(int i = 0; i < paramList->size(); i++)
                {
                        DWORD j;
                        for(j = 0; j < fullList->size; j++)
                        {
-                               if (!_tcsicmp(paramList[i].szName, fullList->data[j].szName))
+                               if (!_tcsicmp(paramList->get(i)->szName, fullList->data[j].szName))
                                        break;
                        }
 
                        if (j == fullList->size)
                        {
-                               memcpy(&fullList->data[j], &paramList[i], sizeof(NXC_AGENT_PARAM));
+                               memcpy(&fullList->data[j], paramList->get(i), sizeof(NXC_AGENT_PARAM));
                                fullList->size++;
                        }
                }
index c50f3e6..a1c9d4a 100644 (file)
@@ -234,47 +234,23 @@ void RegisterDCIFunctions(NXSL_Environment *pEnv)
 // Default constructor for DCItem
 //
 
-DCItem::DCItem()
+DCItem::DCItem() : DCObject()
 {
-   m_dwId = 0;
-   m_dwTemplateId = 0;
-   m_dwTemplateItemId = 0;
    m_dwNumThresholds = 0;
    m_ppThresholdList = NULL;
-   m_busy = 0;
-       m_scheduledForDeletion = 0;
    m_dataType = DCI_DT_INT;
-   m_iPollingInterval = 3600;
-   m_iRetentionTime = 0;
    m_deltaCalculation = DCM_ORIGINAL_VALUE;
-   m_source = DS_INTERNAL;
-   m_status = ITEM_STATUS_NOT_SUPPORTED;
-   m_szName[0] = 0;
-   m_szDescription[0] = 0;
    m_szInstance[0] = 0;
-       m_systemTag[0] = 0;
-   m_tLastPoll = 0;
    m_pszScript = NULL;
    m_pScript = NULL;
-   m_pNode = NULL;
-   m_hMutex = MutexCreateRecursive();
    m_dwCacheSize = 0;
    m_ppValueCache = NULL;
    m_tPrevValueTimeStamp = 0;
-   m_bCacheLoaded = FALSE;
-   m_dwNumSchedules = 0;
-   m_ppScheduleList = NULL;
-   m_tLastCheck = 0;
-       m_flags = 0;
-   m_dwErrorCount = 0;
-       m_dwResourceId = 0;
-       m_dwProxyNode = 0;
+   m_bCacheLoaded = false;
        m_nBaseUnits = DCI_BASEUNITS_OTHER;
        m_nMultiplier = 1;
        m_pszCustomUnitName = NULL;
-       m_pszPerfTabSettings = NULL;
        m_snmpRawValueType = SNMP_RAWTYPE_NONE;
-       m_snmpPort = 0; // use default
 }
 
 
@@ -282,52 +258,24 @@ DCItem::DCItem()
 // Create DCItem from another DCItem
 //
 
-DCItem::DCItem(const DCItem *pSrc)
+DCItem::DCItem(const DCItem *pSrc) : DCObject(pSrc)
 {
    DWORD i;
 
-   m_dwId = pSrc->m_dwId;
-   m_dwTemplateId = pSrc->m_dwTemplateId;
-   m_dwTemplateItemId = pSrc->m_dwTemplateItemId;
-   m_busy = 0;
-       m_scheduledForDeletion = 0;
    m_dataType = pSrc->m_dataType;
-   m_iPollingInterval = pSrc->m_iPollingInterval;
-   m_iRetentionTime = pSrc->m_iRetentionTime;
    m_deltaCalculation = pSrc->m_deltaCalculation;
-   m_source = pSrc->m_source;
-   m_status = pSrc->m_status;
-   m_tLastPoll = 0;
-       _tcscpy(m_szName, pSrc->m_szName);
-       _tcscpy(m_szDescription, pSrc->m_szDescription);
        _tcscpy(m_szInstance, pSrc->m_szInstance);
-       _tcscpy(m_systemTag, pSrc->m_systemTag);
    m_pszScript = NULL;
    m_pScript = NULL;
    setTransformationScript(pSrc->m_pszScript);
-   m_pNode = NULL;
-   m_hMutex = MutexCreateRecursive();
    m_dwCacheSize = 0;
    m_ppValueCache = NULL;
    m_tPrevValueTimeStamp = 0;
-   m_bCacheLoaded = FALSE;
-   m_tLastCheck = 0;
-   m_dwErrorCount = 0;
-       m_flags = pSrc->m_flags;
-       m_dwResourceId = pSrc->m_dwResourceId;
-       m_dwProxyNode = pSrc->m_dwProxyNode;
+   m_bCacheLoaded = false;
        m_nBaseUnits = pSrc->m_nBaseUnits;
        m_nMultiplier = pSrc->m_nMultiplier;
        m_pszCustomUnitName = (pSrc->m_pszCustomUnitName != NULL) ? _tcsdup(pSrc->m_pszCustomUnitName) : NULL;
-       m_pszPerfTabSettings = (pSrc->m_pszPerfTabSettings != NULL) ? _tcsdup(pSrc->m_pszPerfTabSettings) : NULL;
        m_snmpRawValueType = pSrc->m_snmpRawValueType;
-       m_snmpPort = pSrc->m_snmpPort;
-
-   // Copy schedules
-   m_dwNumSchedules = pSrc->m_dwNumSchedules;
-   m_ppScheduleList = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumSchedules);
-   for(i = 0; i < m_dwNumSchedules; i++)
-      m_ppScheduleList[i] = _tcsdup(pSrc->m_ppScheduleList[i]);
 
    // Copy thresholds
    m_dwNumThresholds = pSrc->m_dwNumThresholds;
@@ -349,7 +297,7 @@ DCItem::DCItem(const DCItem *pSrc)
 // custom_units_name,perftab_settings,system_tag,snmp_port,snmp_raw_value_type
 //
 
-DCItem::DCItem(DB_RESULT hResult, int iRow, Template *pNode)
+DCItem::DCItem(DB_RESULT hResult, int iRow, Template *pNode) : DCObject()
 {
    TCHAR *pszTmp, szQuery[256], szBuffer[MAX_DB_STRING];
    DB_RESULT hTempResult;
@@ -382,7 +330,7 @@ DCItem::DCItem(DB_RESULT hResult, int iRow, Template *pNode)
    m_dwCacheSize = 0;
    m_ppValueCache = NULL;
    m_tPrevValueTimeStamp = 0;
-   m_bCacheLoaded = FALSE;
+   m_bCacheLoaded = false;
    m_tLastCheck = 0;
    m_dwErrorCount = 0;
    m_flags = (WORD)DBGetFieldLong(hResult, iRow, 13);
@@ -447,49 +395,23 @@ DCItem::DCItem(DB_RESULT hResult, int iRow, Template *pNode)
 DCItem::DCItem(DWORD dwId, const TCHAR *szName, int iSource, int iDataType, 
                int iPollingInterval, int iRetentionTime, Template *pNode,
                const TCHAR *pszDescription, const TCHAR *systemTag)
+       : DCObject(dwId, szName, iSource, iPollingInterval, iRetentionTime, pNode, pszDescription, systemTag)
 {
-   m_dwId = dwId;
-   m_dwTemplateId = 0;
-   m_dwTemplateItemId = 0;
-   nx_strncpy(m_szName, szName, MAX_ITEM_NAME);
-   if (pszDescription != NULL)
-      nx_strncpy(m_szDescription, pszDescription, MAX_DB_STRING);
-   else
-      _tcscpy(m_szDescription, m_szName);
    m_szInstance[0] = 0;
-       nx_strncpy(m_systemTag, CHECK_NULL_EX(systemTag), MAX_DB_STRING);
-   m_source = iSource;
    m_dataType = iDataType;
-   m_iPollingInterval = iPollingInterval;
-   m_iRetentionTime = iRetentionTime;
    m_deltaCalculation = DCM_ORIGINAL_VALUE;
-   m_status = ITEM_STATUS_ACTIVE;
-   m_busy = 0;
-       m_scheduledForDeletion = 0;
-   m_tLastPoll = 0;
    m_pszScript = NULL;
    m_pScript = NULL;
    m_dwNumThresholds = 0;
    m_ppThresholdList = NULL;
-   m_pNode = pNode;
-   m_hMutex = MutexCreateRecursive();
    m_dwCacheSize = 0;
    m_ppValueCache = NULL;
    m_tPrevValueTimeStamp = 0;
-   m_bCacheLoaded = FALSE;
-   m_flags = 0;
-   m_dwNumSchedules = 0;
-   m_ppScheduleList = NULL;
-   m_tLastCheck = 0;
-   m_dwErrorCount = 0;
-       m_dwResourceId = 0;
-       m_dwProxyNode = 0;
+   m_bCacheLoaded = false;
        m_nBaseUnits = DCI_BASEUNITS_OTHER;
        m_nMultiplier = 1;
        m_pszCustomUnitName = NULL;
-       m_pszPerfTabSettings = NULL;
        m_snmpRawValueType = SNMP_RAWTYPE_NONE;
-       m_snmpPort = 0; // use default
 
    updateCacheSize();
 }
@@ -499,67 +421,25 @@ DCItem::DCItem(DWORD dwId, const TCHAR *szName, int iSource, int iDataType,
 // Create DCItem from import file
 //
 
-DCItem::DCItem(ConfigEntry *config, Template *owner)
+DCItem::DCItem(ConfigEntry *config, Template *owner) : DCObject(config, owner)
 {
-   m_dwId = CreateUniqueId(IDG_ITEM);
-   m_dwTemplateId = 0;
-   m_dwTemplateItemId = 0;
-       nx_strncpy(m_szName, config->getSubEntryValue(_T("name"), 0, _T("unnamed")), MAX_ITEM_NAME);
-   nx_strncpy(m_szDescription, config->getSubEntryValue(_T("description"), 0, m_szName), MAX_DB_STRING);
    nx_strncpy(m_szInstance, config->getSubEntryValue(_T("instance"), 0, _T("")), MAX_DB_STRING);
-       nx_strncpy(m_systemTag, config->getSubEntryValue(_T("systemTag"), 0, _T("")), MAX_DB_STRING);
-       m_source = (BYTE)config->getSubEntryValueInt(_T("origin"));
    m_dataType = (BYTE)config->getSubEntryValueInt(_T("dataType"));
-   m_iPollingInterval = config->getSubEntryValueInt(_T("interval"));
-   m_iRetentionTime = config->getSubEntryValueInt(_T("retention"));
    m_deltaCalculation = (BYTE)config->getSubEntryValueInt(_T("delta"));
-   m_status = ITEM_STATUS_ACTIVE;
-   m_busy = 0;
-       m_scheduledForDeletion = 0;
-       m_flags = 0;
-   m_tLastPoll = 0;
-   m_pNode = owner;
-   m_hMutex = MutexCreateRecursive();
    m_dwCacheSize = 0;
    m_ppValueCache = NULL;
    m_tPrevValueTimeStamp = 0;
-   m_bCacheLoaded = FALSE;
-   m_tLastCheck = 0;
-   m_dwErrorCount = 0;
-       m_dwResourceId = 0;
-       m_dwProxyNode = 0;
+   m_bCacheLoaded = false;
        m_nBaseUnits = DCI_BASEUNITS_OTHER;
        m_nMultiplier = 1;
        m_pszCustomUnitName = NULL;
-       m_pszPerfTabSettings = NULL;
        m_snmpRawValueType = (WORD)config->getSubEntryValueInt(_T("snmpRawValueType"));
-       m_snmpPort = (WORD)config->getSubEntryValueInt(_T("snmpPort"));
 
        if (config->getSubEntryValueInt(_T("allThresholds")))
                m_flags |= DCF_ALL_THRESHOLDS;
        if (config->getSubEntryValueInt(_T("rawValueInOctetString")))
                m_flags |= DCF_RAW_VALUE_OCTET_STRING;
-       if (config->getSubEntryValueInt(_T("advancedSchedule")))
-               m_flags |= DCF_ADVANCED_SCHEDULE;
 
-       ConfigEntry *schedules = config->findEntry(_T("schedules"));
-       if (schedules != NULL)
-               schedules = schedules->findEntry(_T("schedule"));
-       if (schedules != NULL)
-       {
-               m_dwNumSchedules = (DWORD)schedules->getValueCount();
-               m_ppScheduleList = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumSchedules);
-               for(int i = 0; i < (int)m_dwNumSchedules; i++)
-               {
-                       m_ppScheduleList[i] = _tcsdup(schedules->getValue(i));
-               }
-       }
-       else
-       {
-               m_dwNumSchedules = 0;
-               m_ppScheduleList = NULL;
-       }
-   
        m_pszScript = NULL;
        m_pScript = NULL;
        setTransformationScript(config->getSubEntryValue(_T("transformation")));
@@ -592,18 +472,12 @@ DCItem::DCItem(ConfigEntry *config, Template *owner)
 
 DCItem::~DCItem()
 {
-   DWORD i;
-
-   for(i = 0; i < m_dwNumThresholds; i++)
+   for(DWORD i = 0; i < m_dwNumThresholds; i++)
       delete m_ppThresholdList[i];
    safe_free(m_ppThresholdList);
-   for(i = 0; i < m_dwNumSchedules; i++)
-      free(m_ppScheduleList[i]);
-   safe_free(m_ppScheduleList);
    safe_free(m_pszScript);
    delete m_pScript;
        safe_free(m_pszCustomUnitName);
-       safe_free(m_pszPerfTabSettings);
    clearCache();
    MutexDestroy(m_hMutex);
 }
@@ -875,47 +749,26 @@ void DCItem::checkThresholds(ItemValue &value)
 
 
 //
-// Create CSCP message with item data
+// Create NXCP message with item data
 //
 
 void DCItem::createMessage(CSCPMessage *pMsg)
 {
-   DWORD i, dwId;
+       DCObject::createMessage(pMsg);
 
    lock();
-   pMsg->SetVariable(VID_DCI_ID, m_dwId);
-   pMsg->SetVariable(VID_TEMPLATE_ID, m_dwTemplateId);
-   pMsg->SetVariable(VID_NAME, m_szName);
-   pMsg->SetVariable(VID_DESCRIPTION, m_szDescription);
-   pMsg->SetVariable(VID_FLAGS, m_flags);
    pMsg->SetVariable(VID_INSTANCE, m_szInstance);
-   pMsg->SetVariable(VID_SYSTEM_TAG, m_systemTag);
-   pMsg->SetVariable(VID_POLLING_INTERVAL, (DWORD)m_iPollingInterval);
-   pMsg->SetVariable(VID_RETENTION_TIME, (DWORD)m_iRetentionTime);
-   pMsg->SetVariable(VID_DCI_SOURCE_TYPE, (WORD)m_source);
    pMsg->SetVariable(VID_DCI_DATA_TYPE, (WORD)m_dataType);
-   pMsg->SetVariable(VID_DCI_STATUS, (WORD)m_status);
    pMsg->SetVariable(VID_DCI_DELTA_CALCULATION, (WORD)m_deltaCalculation);
    pMsg->SetVariable(VID_DCI_FORMULA, CHECK_NULL_EX(m_pszScript));
-       pMsg->SetVariable(VID_RESOURCE_ID, m_dwResourceId);
-       pMsg->SetVariable(VID_AGENT_PROXY, m_dwProxyNode);
        pMsg->SetVariable(VID_BASE_UNITS, (WORD)m_nBaseUnits);
        pMsg->SetVariable(VID_MULTIPLIER, (DWORD)m_nMultiplier);
        pMsg->SetVariable(VID_SNMP_RAW_VALUE_TYPE, m_snmpRawValueType);
-       pMsg->SetVariable(VID_SNMP_PORT, m_snmpPort);
        if (m_pszCustomUnitName != NULL)
                pMsg->SetVariable(VID_CUSTOM_UNITS_NAME, m_pszCustomUnitName);
-       if (m_pszPerfTabSettings != NULL)
-               pMsg->SetVariable(VID_PERFTAB_SETTINGS, m_pszPerfTabSettings);
    pMsg->SetVariable(VID_NUM_THRESHOLDS, m_dwNumThresholds);
-   for(i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < m_dwNumThresholds; i++, dwId += 10)
+   for(DWORD i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < m_dwNumThresholds; i++, dwId += 10)
       m_ppThresholdList[i]->createMessage(pMsg, dwId);
-   if (m_flags & DCF_ADVANCED_SCHEDULE)
-   {
-      pMsg->SetVariable(VID_NUM_SCHEDULES, m_dwNumSchedules);
-      for(i = 0, dwId = VID_DCI_SCHEDULE_BASE; i < m_dwNumSchedules; i++, dwId++)
-         pMsg->SetVariable(dwId, m_ppScheduleList[i]);
-   }
    unlock();
 }
 
@@ -940,90 +793,46 @@ void DCItem::deleteFromDB()
 
 
 //
-// Update item from CSCP message
+// Update item from NXCP message
 //
 
 void DCItem::updateFromMessage(CSCPMessage *pMsg, DWORD *pdwNumMaps, 
                                DWORD **ppdwMapIndex, DWORD **ppdwMapId)
 {
-   DWORD i, j, dwNum, dwId;
-   Threshold **ppNewList;
-   TCHAR *pszStr;
+       DCObject::updateFromMessage(pMsg);
 
    lock();
 
-   pMsg->GetVariableStr(VID_NAME, m_szName, MAX_ITEM_NAME);
-   pMsg->GetVariableStr(VID_DESCRIPTION, m_szDescription, MAX_DB_STRING);
    pMsg->GetVariableStr(VID_INSTANCE, m_szInstance, MAX_DB_STRING);
-   pMsg->GetVariableStr(VID_SYSTEM_TAG, m_systemTag, MAX_DB_STRING);
-       m_flags = pMsg->GetVariableShort(VID_FLAGS);
-   m_source = (BYTE)pMsg->GetVariableShort(VID_DCI_SOURCE_TYPE);
    m_dataType = (BYTE)pMsg->GetVariableShort(VID_DCI_DATA_TYPE);
-   m_iPollingInterval = pMsg->GetVariableLong(VID_POLLING_INTERVAL);
-   m_iRetentionTime = pMsg->GetVariableLong(VID_RETENTION_TIME);
-   setStatus(pMsg->GetVariableShort(VID_DCI_STATUS), true);
    m_deltaCalculation = (BYTE)pMsg->GetVariableShort(VID_DCI_DELTA_CALCULATION);
-       m_dwResourceId = pMsg->GetVariableLong(VID_RESOURCE_ID);
-       m_dwProxyNode = pMsg->GetVariableLong(VID_AGENT_PROXY);
-   pszStr = pMsg->GetVariableStr(VID_DCI_FORMULA);
+   TCHAR *pszStr = pMsg->GetVariableStr(VID_DCI_FORMULA);
    setTransformationScript(pszStr);
    free(pszStr);
        m_nBaseUnits = pMsg->GetVariableShort(VID_BASE_UNITS);
        m_nMultiplier = (int)pMsg->GetVariableLong(VID_MULTIPLIER);
        safe_free(m_pszCustomUnitName);
        m_pszCustomUnitName = pMsg->GetVariableStr(VID_CUSTOM_UNITS_NAME);
-       safe_free(m_pszPerfTabSettings);
-       m_pszPerfTabSettings = pMsg->GetVariableStr(VID_PERFTAB_SETTINGS);
        m_snmpRawValueType = pMsg->GetVariableShort(VID_SNMP_RAW_VALUE_TYPE);
-       m_snmpPort = pMsg->GetVariableShort(VID_SNMP_PORT);
-
-   // Update schedules
-   for(i = 0; i < m_dwNumSchedules; i++)
-      free(m_ppScheduleList[i]);
-   if (m_flags & DCF_ADVANCED_SCHEDULE)
-   {
-      m_dwNumSchedules = pMsg->GetVariableLong(VID_NUM_SCHEDULES);
-      m_ppScheduleList = (TCHAR **)realloc(m_ppScheduleList, sizeof(TCHAR *) * m_dwNumSchedules);
-      for(i = 0, dwId = VID_DCI_SCHEDULE_BASE; i < m_dwNumSchedules; i++, dwId++)
-      {
-         pszStr = pMsg->GetVariableStr(dwId);
-         if (pszStr != NULL)
-         {
-            m_ppScheduleList[i] = pszStr;
-         }
-         else
-         {
-            m_ppScheduleList[i] = _tcsdup(_T("(null)"));
-         }
-      }
-   }
-   else
-   {
-      if (m_ppScheduleList != NULL)
-      {
-         free(m_ppScheduleList);
-         m_ppScheduleList = NULL;
-      }
-      m_dwNumSchedules = 0;
-   }
 
    // Update thresholds
-   dwNum = pMsg->GetVariableLong(VID_NUM_THRESHOLDS);
+   DWORD dwNum = pMsg->GetVariableLong(VID_NUM_THRESHOLDS);
    DWORD *newThresholds = (DWORD *)malloc(sizeof(DWORD) * dwNum);
    *ppdwMapIndex = (DWORD *)malloc(dwNum * sizeof(DWORD));
    *ppdwMapId = (DWORD *)malloc(dwNum * sizeof(DWORD));
    *pdwNumMaps = 0;
 
    // Read all new threshold ids from message
-   for(i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < dwNum; i++, dwId += 10)
+   for(DWORD i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < dwNum; i++, dwId += 10)
    {
       newThresholds[i] = pMsg->GetVariableLong(dwId);
    }
    
    // Check if some thresholds was deleted, and reposition others if needed
-   ppNewList = (Threshold **)malloc(sizeof(Threshold *) * dwNum);
-   for(i = 0; i < m_dwNumThresholds; i++)
+   Threshold **ppNewList = (Threshold **)malloc(sizeof(Threshold *) * dwNum);
+   for(DWORD i = 0; i < m_dwNumThresholds; i++)
    {
+               DWORD j;
       for(j = 0; j < dwNum; j++)
          if (m_ppThresholdList[i]->getId() == newThresholds[j])
             break;
@@ -1046,7 +855,7 @@ void DCItem::updateFromMessage(CSCPMessage *pMsg, DWORD *pdwNumMaps,
    m_dwNumThresholds = dwNum;
 
    // Add or update thresholds
-   for(i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < dwNum; i++, dwId += 10)
+   for(DWORD i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < dwNum; i++, dwId += 10)
    {
       if (newThresholds[i] == 0)    // New threshold?
       {
@@ -1318,23 +1127,17 @@ void DCItem::transform(ItemValue &value, time_t nElapsedTime)
 
 void DCItem::changeBinding(DWORD dwNewId, Template *pNewNode, BOOL doMacroExpansion)
 {
-   DWORD i;
+       DCObject::changeBinding(dwNewId, pNewNode, doMacroExpansion);
 
    lock();
-   m_pNode = pNewNode;
        if (dwNewId != 0)
        {
-               m_dwId = dwNewId;
-               for(i = 0; i < m_dwNumThresholds; i++)
+               for(DWORD i = 0; i < m_dwNumThresholds; i++)
                        m_ppThresholdList[i]->bindToItem(m_dwId);
        }
 
        if (doMacroExpansion)
-       {
-               expandMacros(m_szName, m_szName, MAX_ITEM_NAME);
-               expandMacros(m_szDescription, m_szDescription, MAX_DB_STRING);
                expandMacros(m_szInstance, m_szInstance, MAX_DB_STRING);
-       }
 
    clearCache();
    updateCacheSize();
@@ -1481,7 +1284,7 @@ void DCItem::updateCacheSize(DWORD dwCondId)
       }
       m_dwCacheSize = dwRequiredSize;
    }
-   m_bCacheLoaded = TRUE;
+   m_bCacheLoaded = true;
 }
 
 
@@ -1619,14 +1422,14 @@ void DCItem::deleteExpiredData()
 // Delete all collected data
 //
 
-BOOL DCItem::deleteAllData()
+bool DCItem::deleteAllData()
 {
    TCHAR szQuery[256];
-       BOOL success;
+       bool success;
 
    lock();
    _sntprintf(szQuery, 256, _T("DELETE FROM idata_%d WHERE item_id=%d"), m_pNode->Id(), m_dwId);
-   success = DBQuery(g_hCoreDB, szQuery);
+       success = DBQuery(g_hCoreDB, szQuery) ? true : false;
        clearCache();
        updateCacheSize();
    unlock();
@@ -1634,218 +1437,6 @@ BOOL DCItem::deleteAllData()
 }
 
 
-//
-// Prepare item for deletion
-//
-
-bool DCItem::prepareForDeletion()
-{
-       DbgPrintf(9, _T("DCItem::prepareForDeletion for DCI %d"), m_dwId);
-
-       lock();
-   m_status = ITEM_STATUS_DISABLED;   // Prevent future polls
-       m_scheduledForDeletion = 1;
-       bool canDelete = (m_busy ? false : true);
-   unlock();
-       DbgPrintf(9, _T("DCItem::prepareForDeletion: completed for DCI %d"), m_dwId);
-
-       return canDelete;
-}
-
-
-//
-// Match schedule element
-// NOTE: We assume that pattern can be modified during processing
-//
-
-static BOOL MatchScheduleElement(TCHAR *pszPattern, int nValue)
-{
-   TCHAR *ptr, *curr;
-   int nStep, nCurr, nPrev;
-   BOOL bRun = TRUE, bRange = FALSE;
-
-   // Check if step was specified
-   ptr = _tcschr(pszPattern, _T('/'));
-   if (ptr != NULL)
-   {
-      *ptr = 0;
-      ptr++;
-      nStep = _tcstol(ptr, NULL, 10);
-   }
-   else
-   {
-      nStep = 1;
-   }
-
-   if (*pszPattern == _T('*'))
-      goto check_step;
-
-   for(curr = pszPattern; bRun; curr = ptr + 1)
-   {
-      for(ptr = curr; (*ptr != 0) && (*ptr != '-') && (*ptr != ','); ptr++);
-      switch(*ptr)
-      {
-         case '-':
-            if (bRange)
-               return FALSE;  // Form like 1-2-3 is invalid
-            bRange = TRUE;
-            *ptr = 0;
-            nPrev = _tcstol(curr, NULL, 10);
-            break;
-         case 0:
-            bRun = FALSE;
-         case ',':
-            *ptr = 0;
-            nCurr = _tcstol(curr, NULL, 10);
-            if (bRange)
-            {
-               if ((nValue >= nPrev) && (nValue <= nCurr))
-                  goto check_step;
-               bRange = FALSE;
-            }
-            else
-            {
-               if (nValue == nCurr)
-                  return TRUE;
-            }
-            break;
-      }
-   }
-
-   return FALSE;
-
-check_step:
-   return (nValue % nStep) == 0;
-}
-
-
-//
-// Match schedule to current time
-//
-
-static BOOL MatchSchedule(struct tm *pCurrTime, TCHAR *pszSchedule)
-{
-   const TCHAR *pszCurr;
-       TCHAR szValue[256];
-
-   // Minute
-   pszCurr = ExtractWord(pszSchedule, szValue);
-   if (!MatchScheduleElement(szValue, pCurrTime->tm_min))
-         return FALSE;
-
-   // Hour
-   pszCurr = ExtractWord(pszCurr, szValue);
-   if (!MatchScheduleElement(szValue, pCurrTime->tm_hour))
-         return FALSE;
-
-   // Day of month
-   pszCurr = ExtractWord(pszCurr, szValue);
-   if (!MatchScheduleElement(szValue, pCurrTime->tm_mday))
-         return FALSE;
-
-   // Month
-   pszCurr = ExtractWord(pszCurr, szValue);
-   if (!MatchScheduleElement(szValue, pCurrTime->tm_mon + 1))
-         return FALSE;
-
-   // Day of week
-   ExtractWord(pszCurr, szValue);
-       for(int i = 0; szValue[i] != 0; i++)
-               if (szValue[i] == _T('7'))
-                       szValue[i] = _T('0');
-   return MatchScheduleElement(szValue, pCurrTime->tm_wday);
-}
-
-
-//
-// Check if associated cluster resource is active. Returns TRUE also if
-// DCI has no resource association
-//
-
-BOOL DCItem::matchClusterResource()
-{
-       Cluster *pCluster;
-
-       if (m_dwResourceId == 0)
-               return TRUE;
-
-       pCluster = ((Node *)m_pNode)->getMyCluster();
-       if (pCluster == NULL)
-               return FALSE;   // Has association, but cluster object cannot be found
-
-       return pCluster->isResourceOnNode(m_dwResourceId, m_pNode->Id());
-}
-
-
-//
-// Set DCI status
-//
-
-void DCItem::setStatus(int status, bool generateEvent)
-{
-       if (generateEvent && (m_pNode != NULL) && (m_status != (BYTE)status))
-       {
-               static DWORD eventCode[3] = { EVENT_DCI_ACTIVE, EVENT_DCI_DISABLED, EVENT_DCI_UNSUPPORTED };
-               static const TCHAR *originName[5] = { _T("Internal"), _T("NetXMS Agent"), _T("SNMP"), _T("CheckPoint SNMP"), _T("Push") };
-
-               PostEvent(eventCode[status], m_pNode->Id(), "dssds", m_dwId, m_szName, m_szDescription,
-                         m_source, originName[m_source]);
-       }
-       m_status = (BYTE)status;
-}
-
-
-//
-// Check if DCI have to be polled
-//
-
-bool DCItem::isReadyForPolling(time_t currTime)
-{
-   bool result;
-
-   lock();
-   if ((m_status != ITEM_STATUS_DISABLED) && (!m_busy) &&
-       m_bCacheLoaded && (m_source != DS_PUSH_AGENT) &&
-                (matchClusterResource()))
-   {
-      if (m_flags & DCF_ADVANCED_SCHEDULE)
-      {
-         DWORD i;
-         struct tm tmCurrLocal, tmLastLocal;
-
-         memcpy(&tmCurrLocal, localtime(&currTime), sizeof(struct tm));
-         memcpy(&tmLastLocal, localtime(&m_tLastCheck), sizeof(struct tm));
-         for(i = 0, result = false; i < m_dwNumSchedules; i++)
-         {
-            if (MatchSchedule(&tmCurrLocal, m_ppScheduleList[i]))
-            {
-               if ((currTime - m_tLastCheck >= 60) ||
-                   (tmCurrLocal.tm_min != tmLastLocal.tm_min))
-               {
-                  result = true;
-                  break;
-               }
-            }
-         }
-         m_tLastCheck = currTime;
-      }
-      else
-      {
-                       if (m_status == ITEM_STATUS_NOT_SUPPORTED)
-                     result = (m_tLastPoll + m_iPollingInterval * 10 <= currTime);
-                       else
-                     result = (m_tLastPoll + m_iPollingInterval <= currTime);
-      }
-   }
-   else
-   {
-      result = false;
-   }
-   unlock();
-   return result;
-}
-
-
 //
 // Update from template item
 //
@@ -2062,18 +1653,6 @@ void DCItem::addThreshold(Threshold *pThreshold)
 }
 
 
-//
-// Add schedule
-//
-
-void DCItem::addSchedule(const TCHAR *pszSchedule)
-{
-       m_dwNumSchedules++;
-       m_ppScheduleList = (TCHAR **)realloc(m_ppScheduleList, sizeof(TCHAR *) * m_dwNumSchedules);
-       m_ppScheduleList[m_dwNumSchedules - 1] = _tcsdup(pszSchedule);
-}
-
-
 //
 // Enumerate all thresholds
 //
@@ -2097,110 +1676,6 @@ BOOL DCItem::enumThresholds(BOOL (* pfCallback)(Threshold *, DWORD, void *), voi
 }
 
 
-//
-// Expand macros in text
-//
-
-void DCItem::expandMacros(const TCHAR *src, TCHAR *dst, size_t dstLen)
-{
-       String temp;
-       TCHAR *head, *rest, *macro;
-       int index = 0, index2;
-
-       temp = src;
-       while((index = temp.find(_T("%{"), index)) != String::npos)
-       {
-               head = temp.subStr(0, index);
-               index2 = temp.find(_T("}"), index);
-               if (index2 == String::npos)
-               {
-                       free(head);
-                       break;  // Missing closing }
-               }
-               rest = temp.subStr(index2 + 1, -1);
-               macro = temp.subStr(index + 2, index2 - index - 2);
-               StrStrip(macro);
-
-               temp = head;
-               if (!_tcscmp(macro, _T("node_id")))
-               {
-                       if (m_pNode != NULL)
-                       {
-                               temp.addFormattedString(_T("%d"), m_pNode->Id());
-                       }
-                       else
-                       {
-                               temp += _T("(error)");
-                       }
-               }
-               else if (!_tcscmp(macro, _T("node_name")))
-               {
-                       if (m_pNode != NULL)
-                       {
-                               temp += m_pNode->Name();
-                       }
-                       else
-                       {
-                               temp += _T("(error)");
-                       }
-               }
-               else if (!_tcscmp(macro, _T("node_primary_ip")))
-               {
-                       if (m_pNode != NULL)
-                       {
-                               TCHAR ipAddr[32];
-
-                               temp += IpToStr(m_pNode->IpAddr(), ipAddr);
-                       }
-                       else
-                       {
-                               temp += _T("(error)");
-                       }
-               }
-               else if (!_tcsncmp(macro, _T("script:"), 7))
-               {
-                       NXSL_Program *script;
-                       NXSL_ServerEnv *pEnv;
-
-             g_pScriptLibrary->lock();
-                       script = g_pScriptLibrary->findScript(&macro[7]);
-                       if (script != NULL)
-                       {
-                               pEnv = new NXSL_ServerEnv;
-                               if (m_pNode != NULL)
-                                       script->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, m_pNode)));
-
-                               if (script->run(pEnv) == 0)
-                               {
-                                       NXSL_Value *result = script->getResult();
-                                       if (result != NULL)
-                                               temp += CHECK_NULL_EX(result->getValueAsCString());
-                        DbgPrintf(4, _T("DCItem::expandMacros(%d,\"%s\"): Script %s executed successfully"), m_dwId, src, &macro[7]);
-                               }
-                               else
-                               {
-                        DbgPrintf(4, _T("DCItem::expandMacros(%d,\"%s\"): Script %s execution error: %s"),
-                                                 m_dwId, src, &macro[7], script->getErrorText());
-                                       PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", &macro[7],
-                                                                script->getErrorText(), m_dwId);
-                               }
-                       }
-                       else
-                       {
-                DbgPrintf(4, _T("DCItem::expandMacros(%d,\"%s\"): Cannot find script %s"), m_dwId, src, &macro[7]);
-                       }
-             g_pScriptLibrary->unlock();
-               }
-               temp += rest;
-               
-               free(head);
-               free(rest);
-               free(macro);
-       }
-       nx_strncpy(dst, temp, dstLen);
-}
-
-
 //
 // Test DCI's transformation script
 // Runs 
@@ -2281,3 +1756,14 @@ void DCItem::fillMessageWithThresholds(CSCPMessage *msg)
 
        unlock();
 }
+
+
+//
+// Returns true if internal cache is loaded. If data collection object
+// does not have cache should return true
+//
+
+bool DCItem::isCacheLoaded()
+{
+       return m_bCacheLoaded;
+}
diff --git a/src/server/core/dcobject.cpp b/src/server/core/dcobject.cpp
new file mode 100644 (file)
index 0000000..c522234
--- /dev/null
@@ -0,0 +1,706 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003-2012 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: dcobject.cpp
+**
+**/
+
+#include "nxcore.h"
+
+
+//
+// Default constructor for DCObject
+//
+
+DCObject::DCObject()
+{
+   m_dwId = 0;
+   m_dwTemplateId = 0;
+   m_dwTemplateItemId = 0;
+   m_busy = 0;
+       m_scheduledForDeletion = 0;
+   m_iPollingInterval = 3600;
+   m_iRetentionTime = 0;
+   m_source = DS_INTERNAL;
+   m_status = ITEM_STATUS_NOT_SUPPORTED;
+   m_szName[0] = 0;
+   m_szDescription[0] = 0;
+       m_systemTag[0] = 0;
+   m_tLastPoll = 0;
+   m_pNode = NULL;
+   m_hMutex = MutexCreateRecursive();
+   m_dwNumSchedules = 0;
+   m_ppScheduleList = NULL;
+   m_tLastCheck = 0;
+       m_flags = 0;
+   m_dwErrorCount = 0;
+       m_dwResourceId = 0;
+       m_dwProxyNode = 0;
+       m_pszPerfTabSettings = NULL;
+       m_snmpPort = 0; // use default
+}
+
+
+//
+// Create DCObject from another DCObject
+//
+
+DCObject::DCObject(const DCObject *pSrc)
+{
+   DWORD i;
+
+   m_dwId = pSrc->m_dwId;
+   m_dwTemplateId = pSrc->m_dwTemplateId;
+   m_dwTemplateItemId = pSrc->m_dwTemplateItemId;
+   m_busy = 0;
+       m_scheduledForDeletion = 0;
+   m_iPollingInterval = pSrc->m_iPollingInterval;
+   m_iRetentionTime = pSrc->m_iRetentionTime;
+   m_source = pSrc->m_source;
+   m_status = pSrc->m_status;
+   m_tLastPoll = 0;
+       _tcscpy(m_szName, pSrc->m_szName);
+       _tcscpy(m_szDescription, pSrc->m_szDescription);
+       _tcscpy(m_systemTag, pSrc->m_systemTag);
+   m_pNode = NULL;
+   m_hMutex = MutexCreateRecursive();
+   m_tLastCheck = 0;
+   m_dwErrorCount = 0;
+       m_flags = pSrc->m_flags;
+       m_dwResourceId = pSrc->m_dwResourceId;
+       m_dwProxyNode = pSrc->m_dwProxyNode;
+       m_pszPerfTabSettings = (pSrc->m_pszPerfTabSettings != NULL) ? _tcsdup(pSrc->m_pszPerfTabSettings) : NULL;
+       m_snmpPort = pSrc->m_snmpPort;
+
+   // Copy schedules
+   m_dwNumSchedules = pSrc->m_dwNumSchedules;
+   m_ppScheduleList = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumSchedules);
+   for(i = 0; i < m_dwNumSchedules; i++)
+      m_ppScheduleList[i] = _tcsdup(pSrc->m_ppScheduleList[i]);
+}
+
+
+//
+// Constructor for creating new DCObject from scratch
+//
+
+DCObject::DCObject(DWORD dwId, const TCHAR *szName, int iSource, 
+               int iPollingInterval, int iRetentionTime, Template *pNode,
+               const TCHAR *pszDescription, const TCHAR *systemTag)
+{
+   m_dwId = dwId;
+   m_dwTemplateId = 0;
+   m_dwTemplateItemId = 0;
+   nx_strncpy(m_szName, szName, MAX_ITEM_NAME);
+   if (pszDescription != NULL)
+      nx_strncpy(m_szDescription, pszDescription, MAX_DB_STRING);
+   else
+      _tcscpy(m_szDescription, m_szName);
+       nx_strncpy(m_systemTag, CHECK_NULL_EX(systemTag), MAX_DB_STRING);
+   m_source = iSource;
+   m_iPollingInterval = iPollingInterval;
+   m_iRetentionTime = iRetentionTime;
+   m_status = ITEM_STATUS_ACTIVE;
+   m_busy = 0;
+       m_scheduledForDeletion = 0;
+   m_tLastPoll = 0;
+   m_pNode = pNode;
+   m_hMutex = MutexCreateRecursive();
+   m_flags = 0;
+   m_dwNumSchedules = 0;
+   m_ppScheduleList = NULL;
+   m_tLastCheck = 0;
+   m_dwErrorCount = 0;
+       m_dwResourceId = 0;
+       m_dwProxyNode = 0;
+       m_pszPerfTabSettings = NULL;
+       m_snmpPort = 0; // use default
+}
+
+
+//
+// Create DCObject from import file
+//
+
+DCObject::DCObject(ConfigEntry *config, Template *owner)
+{
+   m_dwId = CreateUniqueId(IDG_ITEM);
+   m_dwTemplateId = 0;
+   m_dwTemplateItemId = 0;
+       nx_strncpy(m_szName, config->getSubEntryValue(_T("name"), 0, _T("unnamed")), MAX_ITEM_NAME);
+   nx_strncpy(m_szDescription, config->getSubEntryValue(_T("description"), 0, m_szName), MAX_DB_STRING);
+       nx_strncpy(m_systemTag, config->getSubEntryValue(_T("systemTag"), 0, _T("")), MAX_DB_STRING);
+       m_source = (BYTE)config->getSubEntryValueInt(_T("origin"));
+   m_iPollingInterval = config->getSubEntryValueInt(_T("interval"));
+   m_iRetentionTime = config->getSubEntryValueInt(_T("retention"));
+   m_status = ITEM_STATUS_ACTIVE;
+   m_busy = 0;
+       m_scheduledForDeletion = 0;
+       m_flags = 0;
+   m_tLastPoll = 0;
+   m_pNode = owner;
+   m_hMutex = MutexCreateRecursive();
+   m_tLastCheck = 0;
+   m_dwErrorCount = 0;
+       m_dwResourceId = 0;
+       m_dwProxyNode = 0;
+       m_pszPerfTabSettings = NULL;
+       m_snmpPort = (WORD)config->getSubEntryValueInt(_T("snmpPort"));
+
+       if (config->getSubEntryValueInt(_T("advancedSchedule")))
+               m_flags |= DCF_ADVANCED_SCHEDULE;
+
+       ConfigEntry *schedules = config->findEntry(_T("schedules"));
+       if (schedules != NULL)
+               schedules = schedules->findEntry(_T("schedule"));
+       if (schedules != NULL)
+       {
+               m_dwNumSchedules = (DWORD)schedules->getValueCount();
+               m_ppScheduleList = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumSchedules);
+               for(int i = 0; i < (int)m_dwNumSchedules; i++)
+               {
+                       m_ppScheduleList[i] = _tcsdup(schedules->getValue(i));
+               }
+       }
+       else
+       {
+               m_dwNumSchedules = 0;
+               m_ppScheduleList = NULL;
+       }
+}
+
+
+//
+// Destructor
+//
+
+DCObject::~DCObject()
+{
+   for(DWORD i = 0; i < m_dwNumSchedules; i++)
+      free(m_ppScheduleList[i]);
+   safe_free(m_ppScheduleList);
+       safe_free(m_pszPerfTabSettings);
+   MutexDestroy(m_hMutex);
+}
+
+
+//
+// Check if associated cluster resource is active. Returns true also if
+// DCI has no resource association
+//
+
+bool DCObject::matchClusterResource()
+{
+       Cluster *pCluster;
+
+       if (m_dwResourceId == 0)
+               return true;
+
+       pCluster = ((Node *)m_pNode)->getMyCluster();
+       if (pCluster == NULL)
+               return false;   // Has association, but cluster object cannot be found
+
+       return pCluster->isResourceOnNode(m_dwResourceId, m_pNode->Id());
+}
+
+
+//
+// Expand macros in text
+//
+
+void DCObject::expandMacros(const TCHAR *src, TCHAR *dst, size_t dstLen)
+{
+       String temp;
+       TCHAR *head, *rest, *macro;
+       int index = 0, index2;
+
+       temp = src;
+       while((index = temp.find(_T("%{"), index)) != String::npos)
+       {
+               head = temp.subStr(0, index);
+               index2 = temp.find(_T("}"), index);
+               if (index2 == String::npos)
+               {
+                       free(head);
+                       break;  // Missing closing }
+               }
+               rest = temp.subStr(index2 + 1, -1);
+               macro = temp.subStr(index + 2, index2 - index - 2);
+               StrStrip(macro);
+
+               temp = head;
+               if (!_tcscmp(macro, _T("node_id")))
+               {
+                       if (m_pNode != NULL)
+                       {
+                               temp.addFormattedString(_T("%d"), m_pNode->Id());
+                       }
+                       else
+                       {
+                               temp += _T("(error)");
+                       }
+               }
+               else if (!_tcscmp(macro, _T("node_name")))
+               {
+                       if (m_pNode != NULL)
+                       {
+                               temp += m_pNode->Name();
+                       }
+                       else
+                       {
+                               temp += _T("(error)");
+                       }
+               }
+               else if (!_tcscmp(macro, _T("node_primary_ip")))
+               {
+                       if (m_pNode != NULL)
+                       {
+                               TCHAR ipAddr[32];
+
+                               temp += IpToStr(m_pNode->IpAddr(), ipAddr);
+                       }
+                       else
+                       {
+                               temp += _T("(error)");
+                       }
+               }
+               else if (!_tcsncmp(macro, _T("script:"), 7))
+               {
+                       NXSL_Program *script;
+                       NXSL_ServerEnv *pEnv;
+
+             g_pScriptLibrary->lock();
+                       script = g_pScriptLibrary->findScript(&macro[7]);
+                       if (script != NULL)
+                       {
+                               pEnv = new NXSL_ServerEnv;
+                               if (m_pNode != NULL)
+                                       script->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, m_pNode)));
+
+                               if (script->run(pEnv) == 0)
+                               {
+                                       NXSL_Value *result = script->getResult();
+                                       if (result != NULL)
+                                               temp += CHECK_NULL_EX(result->getValueAsCString());
+                        DbgPrintf(4, _T("DCItem::expandMacros(%d,\"%s\"): Script %s executed successfully"), m_dwId, src, &macro[7]);
+                               }
+                               else
+                               {
+                        DbgPrintf(4, _T("DCItem::expandMacros(%d,\"%s\"): Script %s execution error: %s"),
+                                                 m_dwId, src, &macro[7], script->getErrorText());
+                                       PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", &macro[7],
+                                                                script->getErrorText(), m_dwId);
+                               }
+                       }
+                       else
+                       {
+                DbgPrintf(4, _T("DCItem::expandMacros(%d,\"%s\"): Cannot find script %s"), m_dwId, src, &macro[7]);
+                       }
+             g_pScriptLibrary->unlock();
+               }
+               temp += rest;
+               
+               free(head);
+               free(rest);
+               free(macro);
+       }
+       nx_strncpy(dst, temp, dstLen);
+}
+
+
+//
+// Delete all collected data
+//
+
+bool DCObject::deleteAllData()
+{
+       return false;
+}
+
+
+//
+// Clean expired data
+//
+
+void DCObject::deleteExpiredData()
+{
+}
+
+
+//
+// Add schedule
+//
+
+void DCObject::addSchedule(const TCHAR *pszSchedule)
+{
+       m_dwNumSchedules++;
+       m_ppScheduleList = (TCHAR **)realloc(m_ppScheduleList, sizeof(TCHAR *) * m_dwNumSchedules);
+       m_ppScheduleList[m_dwNumSchedules - 1] = _tcsdup(pszSchedule);
+}
+
+
+//
+// Set new ID and node/template association
+//
+
+void DCObject::changeBinding(DWORD dwNewId, Template *pNewNode, BOOL doMacroExpansion)
+{
+   lock();
+   m_pNode = pNewNode;
+       if (dwNewId != 0)
+               m_dwId = dwNewId;
+
+       if (doMacroExpansion)
+       {
+               expandMacros(m_szName, m_szName, MAX_ITEM_NAME);
+               expandMacros(m_szDescription, m_szDescription, MAX_DB_STRING);
+       }
+
+   unlock();
+}
+
+
+//
+// Set DCI status
+//
+
+void DCObject::setStatus(int status, bool generateEvent)
+{
+       if (generateEvent && (m_pNode != NULL) && (m_status != (BYTE)status))
+       {
+               static DWORD eventCode[3] = { EVENT_DCI_ACTIVE, EVENT_DCI_DISABLED, EVENT_DCI_UNSUPPORTED };
+               static const TCHAR *originName[5] = { _T("Internal"), _T("NetXMS Agent"), _T("SNMP"), _T("CheckPoint SNMP"), _T("Push") };
+
+               PostEvent(eventCode[status], m_pNode->Id(), "dssds", m_dwId, m_szName, m_szDescription,
+                         m_source, originName[m_source]);
+       }
+       m_status = (BYTE)status;
+}
+
+
+//
+// Match schedule element
+// NOTE: We assume that pattern can be modified during processing
+//
+
+static BOOL MatchScheduleElement(TCHAR *pszPattern, int nValue)
+{
+   TCHAR *ptr, *curr;
+   int nStep, nCurr, nPrev;
+   BOOL bRun = TRUE, bRange = FALSE;
+
+   // Check if step was specified
+   ptr = _tcschr(pszPattern, _T('/'));
+   if (ptr != NULL)
+   {
+      *ptr = 0;
+      ptr++;
+      nStep = _tcstol(ptr, NULL, 10);
+   }
+   else
+   {
+      nStep = 1;
+   }
+
+   if (*pszPattern == _T('*'))
+      goto check_step;
+
+   for(curr = pszPattern; bRun; curr = ptr + 1)
+   {
+      for(ptr = curr; (*ptr != 0) && (*ptr != '-') && (*ptr != ','); ptr++);
+      switch(*ptr)
+      {
+         case '-':
+            if (bRange)
+               return FALSE;  // Form like 1-2-3 is invalid
+            bRange = TRUE;
+            *ptr = 0;
+            nPrev = _tcstol(curr, NULL, 10);
+            break;
+         case 0:
+            bRun = FALSE;
+         case ',':
+            *ptr = 0;
+            nCurr = _tcstol(curr, NULL, 10);
+            if (bRange)
+            {
+               if ((nValue >= nPrev) && (nValue <= nCurr))
+                  goto check_step;
+               bRange = FALSE;
+            }
+            else
+            {
+               if (nValue == nCurr)
+                  return TRUE;
+            }
+            break;
+      }
+   }
+
+   return FALSE;
+
+check_step:
+   return (nValue % nStep) == 0;
+}
+
+
+//
+// Match schedule to current time
+//
+
+static BOOL MatchSchedule(struct tm *pCurrTime, TCHAR *pszSchedule)
+{
+   const TCHAR *pszCurr;
+       TCHAR szValue[256];
+
+   // Minute
+   pszCurr = ExtractWord(pszSchedule, szValue);
+   if (!MatchScheduleElement(szValue, pCurrTime->tm_min))
+         return FALSE;
+
+   // Hour
+   pszCurr = ExtractWord(pszCurr, szValue);
+   if (!MatchScheduleElement(szValue, pCurrTime->tm_hour))
+         return FALSE;
+
+   // Day of month
+   pszCurr = ExtractWord(pszCurr, szValue);
+   if (!MatchScheduleElement(szValue, pCurrTime->tm_mday))
+         return FALSE;
+
+   // Month
+   pszCurr = ExtractWord(pszCurr, szValue);
+   if (!MatchScheduleElement(szValue, pCurrTime->tm_mon + 1))
+         return FALSE;
+
+   // Day of week
+   ExtractWord(pszCurr, szValue);
+       for(int i = 0; szValue[i] != 0; i++)
+               if (szValue[i] == _T('7'))
+                       szValue[i] = _T('0');
+   return MatchScheduleElement(szValue, pCurrTime->tm_wday);
+}
+
+
+//
+// Check if data collection object have to be polled
+//
+
+bool DCObject::isReadyForPolling(time_t currTime)
+{
+   bool result;
+
+   lock();
+   if ((m_status != ITEM_STATUS_DISABLED) && (!m_busy) &&
+       isCacheLoaded() && (m_source != DS_PUSH_AGENT) &&
+                (matchClusterResource()))
+   {
+      if (m_flags & DCF_ADVANCED_SCHEDULE)
+      {
+         DWORD i;
+         struct tm tmCurrLocal, tmLastLocal;
+
+         memcpy(&tmCurrLocal, localtime(&currTime), sizeof(struct tm));
+         memcpy(&tmLastLocal, localtime(&m_tLastCheck), sizeof(struct tm));
+         for(i = 0, result = false; i < m_dwNumSchedules; i++)
+         {
+            if (MatchSchedule(&tmCurrLocal, m_ppScheduleList[i]))
+            {
+               if ((currTime - m_tLastCheck >= 60) ||
+                   (tmCurrLocal.tm_min != tmLastLocal.tm_min))
+               {
+                  result = true;
+                  break;
+               }
+            }
+         }
+         m_tLastCheck = currTime;
+      }
+      else
+      {
+                       if (m_status == ITEM_STATUS_NOT_SUPPORTED)
+                     result = (m_tLastPoll + m_iPollingInterval * 10 <= currTime);
+                       else
+                     result = (m_tLastPoll + m_iPollingInterval <= currTime);
+      }
+   }
+   else
+   {
+      result = false;
+   }
+   unlock();
+   return result;
+}
+
+
+//
+// Returns true if internal cache is loaded. If data collection object
+// does not have cache should return true
+//
+
+bool DCObject::isCacheLoaded()
+{
+       return true;
+}
+
+
+//
+// Prepare object for deletion
+//
+
+bool DCObject::prepareForDeletion()
+{
+       DbgPrintf(9, _T("DCObject::prepareForDeletion for DCO %d"), m_dwId);
+
+       lock();
+   m_status = ITEM_STATUS_DISABLED;   // Prevent future polls
+       m_scheduledForDeletion = 1;
+       bool canDelete = (m_busy ? false : true);
+   unlock();
+       DbgPrintf(9, _T("DCObject::prepareForDeletion: completed for DCO %d, canDelete=%d"), m_dwId, (int)canDelete);
+
+       return canDelete;
+}
+
+
+//
+// Create NXCP message with object data
+//
+
+void DCObject::createMessage(CSCPMessage *pMsg)
+{
+       lock();
+   pMsg->SetVariable(VID_DCI_ID, m_dwId);
+   pMsg->SetVariable(VID_TEMPLATE_ID, m_dwTemplateId);
+   pMsg->SetVariable(VID_NAME, m_szName);
+   pMsg->SetVariable(VID_DESCRIPTION, m_szDescription);
+   pMsg->SetVariable(VID_FLAGS, m_flags);
+   pMsg->SetVariable(VID_SYSTEM_TAG, m_systemTag);
+   pMsg->SetVariable(VID_POLLING_INTERVAL, (DWORD)m_iPollingInterval);
+   pMsg->SetVariable(VID_RETENTION_TIME, (DWORD)m_iRetentionTime);
+   pMsg->SetVariable(VID_DCI_SOURCE_TYPE, (WORD)m_source);
+   pMsg->SetVariable(VID_DCI_STATUS, (WORD)m_status);
+       pMsg->SetVariable(VID_RESOURCE_ID, m_dwResourceId);
+       pMsg->SetVariable(VID_AGENT_PROXY, m_dwProxyNode);
+       pMsg->SetVariable(VID_SNMP_PORT, m_snmpPort);
+       if (m_pszPerfTabSettings != NULL)
+               pMsg->SetVariable(VID_PERFTAB_SETTINGS, m_pszPerfTabSettings);
+   if (m_flags & DCF_ADVANCED_SCHEDULE)
+   {
+      pMsg->SetVariable(VID_NUM_SCHEDULES, m_dwNumSchedules);
+      for(DWORD i = 0, dwId = VID_DCI_SCHEDULE_BASE; i < m_dwNumSchedules; i++, dwId++)
+         pMsg->SetVariable(dwId, m_ppScheduleList[i]);
+   }
+   unlock();
+}
+
+
+//
+// Update data collection object from NXCP message
+//
+
+void DCObject::updateFromMessage(CSCPMessage *pMsg)
+{
+   lock();
+
+   pMsg->GetVariableStr(VID_NAME, m_szName, MAX_ITEM_NAME);
+   pMsg->GetVariableStr(VID_DESCRIPTION, m_szDescription, MAX_DB_STRING);
+   pMsg->GetVariableStr(VID_SYSTEM_TAG, m_systemTag, MAX_DB_STRING);
+       m_flags = pMsg->GetVariableShort(VID_FLAGS);
+   m_source = (BYTE)pMsg->GetVariableShort(VID_DCI_SOURCE_TYPE);
+   m_iPollingInterval = pMsg->GetVariableLong(VID_POLLING_INTERVAL);
+   m_iRetentionTime = pMsg->GetVariableLong(VID_RETENTION_TIME);
+   setStatus(pMsg->GetVariableShort(VID_DCI_STATUS), true);
+       m_dwResourceId = pMsg->GetVariableLong(VID_RESOURCE_ID);
+       m_dwProxyNode = pMsg->GetVariableLong(VID_AGENT_PROXY);
+       safe_free(m_pszPerfTabSettings);
+       m_pszPerfTabSettings = pMsg->GetVariableStr(VID_PERFTAB_SETTINGS);
+       m_snmpPort = pMsg->GetVariableShort(VID_SNMP_PORT);
+
+   // Update schedules
+   for(DWORD i = 0; i < m_dwNumSchedules; i++)
+      free(m_ppScheduleList[i]);
+
+   if (m_flags & DCF_ADVANCED_SCHEDULE)
+   {
+      m_dwNumSchedules = pMsg->GetVariableLong(VID_NUM_SCHEDULES);
+      m_ppScheduleList = (TCHAR **)realloc(m_ppScheduleList, sizeof(TCHAR *) * m_dwNumSchedules);
+      for(DWORD i = 0, dwId = VID_DCI_SCHEDULE_BASE; i < m_dwNumSchedules; i++, dwId++)
+      {
+         TCHAR *pszStr = pMsg->GetVariableStr(dwId);
+         if (pszStr != NULL)
+         {
+            m_ppScheduleList[i] = pszStr;
+         }
+         else
+         {
+            m_ppScheduleList[i] = _tcsdup(_T("(null)"));
+         }
+      }
+   }
+   else
+   {
+      if (m_ppScheduleList != NULL)
+      {
+         free(m_ppScheduleList);
+         m_ppScheduleList = NULL;
+      }
+      m_dwNumSchedules = 0;
+   }
+
+       unlock();
+}
+
+
+//
+// Save to database
+//
+
+BOOL DCObject::saveToDB(DB_HANDLE hdb)
+{
+       return FALSE;
+}
+
+
+//
+// Delete object and collected data from database
+//
+
+void DCObject::deleteFromDB()
+{
+}
+
+
+//
+// Get list of used events
+//
+
+void DCObject::getEventList(DWORD **ppdwList, DWORD *pdwSize)
+{
+       *ppdwList = NULL;
+       *pdwSize = 0;
+}
+
+
+//
+// Create management pack record
+//
+
+void DCObject::createNXMPRecord(String &str)
+{
+}
index a81fada..20e269d 100644 (file)
@@ -216,12 +216,19 @@ BOOL InitIdTable()
       DBFreeResult(hResult);
    }
 
-   // Get first available data collection item id
+   // Get first available data collection object id
    hResult = DBSelect(g_hCoreDB, _T("SELECT max(item_id) FROM items"));
    if (hResult != NULL)
    {
       if (DBGetNumRows(hResult) > 0)
-         m_dwFreeIdTable[IDG_ITEM] = max(1, DBGetFieldULong(hResult, 0, 0) + 1);
+         m_dwFreeIdTable[IDG_ITEM] = max(m_dwFreeIdTable[IDG_ITEM], DBGetFieldULong(hResult, 0, 0) + 1);
+      DBFreeResult(hResult);
+   }
+   hResult = DBSelect(g_hCoreDB, _T("SELECT max(item_id) FROM dc_tables"));
+   if (hResult != NULL)
+   {
+      if (DBGetNumRows(hResult) > 0)
+         m_dwFreeIdTable[IDG_ITEM] = max(m_dwFreeIdTable[IDG_ITEM], DBGetFieldULong(hResult, 0, 0) + 1);
       DBFreeResult(hResult);
    }
 
index c03a4b6..de1cb90 100644 (file)
@@ -60,8 +60,8 @@ Node::Node() : Template()
        m_sysDescription = NULL;
        m_sysName = NULL;
        m_lldpNodeId = NULL;
-   m_dwNumParams = 0;
-   m_pParamList = NULL;
+   m_paramList = NULL;
+       m_tableList = NULL;
    m_dwPollerNode = 0;
    m_dwProxyNode = 0;
        m_dwSNMPProxy = 0;
@@ -126,8 +126,8 @@ Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwProxyNode, DWORD dwSNMPProxy, DW
        m_sysDescription = NULL;
        m_sysName = NULL;
        m_lldpNodeId = NULL;
-   m_dwNumParams = 0;
-   m_pParamList = NULL;
+   m_paramList = NULL;
+       m_tableList = NULL;
    m_dwPollerNode = 0;
    m_dwProxyNode = dwProxyNode;
        m_dwSNMPProxy = dwSNMPProxy;
@@ -165,7 +165,8 @@ Node::~Node()
    MutexDestroy(m_mutexRTAccess);
        MutexDestroy(m_mutexTopoAccess);
    delete m_pAgentConnection;
-   safe_free(m_pParamList);
+   delete m_paramList;
+       delete m_tableList;
        safe_free(m_sysDescription);
    DestroyRoutingTable(m_pRoutingTable);
        if (m_linkLayerNeighbors != NULL)
@@ -1393,8 +1394,7 @@ static DWORD PrintMIBWalkerCallback(DWORD version, SNMP_Variable *var, SNMP_Tran
 void Node::configurationPoll(ClientSession *pSession, DWORD dwRqId,
                              int nPoller, DWORD dwNetMask)
 {
-   DWORD dwOldFlags = m_dwFlags, dwAddr, rcc, dwNumParams;
-       NXC_AGENT_PARAM *pParamList;
+   DWORD dwOldFlags = m_dwFlags, dwAddr, rcc;
    AgentConnection *pAgentConn;
    TCHAR szBuffer[4096];
        SNMP_Transport *pTransport;
@@ -1512,18 +1512,21 @@ void Node::configurationPoll(ClientSession *pSession, DWORD dwRqId,
                UnlockData();
                                }
 
-            rcc = pAgentConn->getSupportedParameters(&dwNumParams, &pParamList);
+                               StructArray<NXC_AGENT_PARAM> *plist;
+                               StructArray<NXC_AGENT_TABLE> *tlist;
+            rcc = pAgentConn->getSupportedParameters(&plist, &tlist);
                                if (rcc == ERR_SUCCESS)
                                {
                                        LockData();
-                                       safe_free(m_pParamList);
-                                       m_dwNumParams = dwNumParams;
-                                       m_pParamList = pParamList;
+                                       delete m_paramList;
+                                       delete m_tableList;
+                                       m_paramList = plist;
+                                       m_tableList = tlist;
                                        UnlockData();
                                }
                                else
                                {
-                                  DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::GetSupportedParameters() failed: rcc=%d"), m_szName, rcc);
+                                  DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getSupportedParameters() failed: rcc=%d"), m_szName, rcc);
                                }
 
                                checkAgentPolicyBinding(pAgentConn);
@@ -3088,28 +3091,53 @@ int Node::getInterfaceStatusFromAgent(DWORD dwIndex)
 // Put list of supported parameters into CSCP message
 //
 
-void Node::WriteParamListToMessage(CSCPMessage *pMsg)
+void Node::writeParamListToMessage(CSCPMessage *pMsg)
 {
-   DWORD i, dwId;
-
    LockData();
-   if (m_pParamList != NULL)
+
+       if (m_paramList != NULL)
    {
-      pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
-      for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
+      pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)m_paramList->size());
+
+               int i;
+               DWORD dwId;
+      for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_paramList->size(); i++)
       {
-         pMsg->SetVariable(dwId++, m_pParamList[i].szName);
-         pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
-         pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
+                       NXC_AGENT_PARAM *p = m_paramList->get(i);
+         pMsg->SetVariable(dwId++, p->szName);
+         pMsg->SetVariable(dwId++, p->szDescription);
+         pMsg->SetVariable(dwId++, (WORD)p->iDataType);
       }
-               DbgPrintf(6, _T("Node[%s]::WriteParamListToMessage(): sending %d parameters"), m_szName, m_dwNumParams);
+               DbgPrintf(6, _T("Node[%s]::writeParamListToMessage(): sending %d parameters"), m_szName, m_paramList->size());
    }
    else
    {
-               DbgPrintf(6, _T("Node[%s]::WriteParamListToMessage(): m_pParamList == NULL"), m_szName);
+               DbgPrintf(6, _T("Node[%s]::writeParamListToMessage(): m_paramList == NULL"), m_szName);
       pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
    }
-   UnlockData();
+
+       if (m_tableList != NULL)
+   {
+               pMsg->SetVariable(VID_NUM_TABLES, (DWORD)m_tableList->size());
+
+               int i;
+               DWORD dwId;
+      for(i = 0, dwId = VID_TABLE_LIST_BASE; i < m_tableList->size(); i++)
+      {
+                       NXC_AGENT_TABLE *t = m_tableList->get(i);
+         pMsg->SetVariable(dwId++, t->name);
+         pMsg->SetVariable(dwId++, t->instanceColumn);
+         pMsg->SetVariable(dwId++, t->description);
+      }
+               DbgPrintf(6, _T("Node[%s]::writeParamListToMessage(): sending %d tables"), m_szName, m_tableList->size());
+   }
+   else
+   {
+               DbgPrintf(6, _T("Node[%s]::writeParamListToMessage(): m_tableList == NULL"), m_szName);
+      pMsg->SetVariable(VID_NUM_TABLES, (DWORD)0);
+   }
+
+       UnlockData();
 }
 
 
@@ -3117,11 +3145,10 @@ void Node::WriteParamListToMessage(CSCPMessage *pMsg)
 // Open list of supported parameters for reading
 //
 
-void Node::openParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
+void Node::openParamList(StructArray<NXC_AGENT_PARAM> **paramList)
 {
    LockData();
-   *pdwNumParams = m_dwNumParams;
-   *ppParamList = m_pParamList;
+   *paramList = m_paramList;
 }
 
 
index fe5826c..d9ad951 100644 (file)
                                RelativePath=".\dcivalue.cpp"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\dcobject.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\debug.cpp"\r
                                >\r
index 5b463d2..409e1ca 100644 (file)
@@ -5523,7 +5523,7 @@ void ClientSession::SendParametersList(CSCPMessage *pRequest)
       {
          case OBJECT_NODE:
             msg.SetVariable(VID_RCC, RCC_SUCCESS);
-            ((Node *)pObject)->WriteParamListToMessage(&msg);
+            ((Node *)pObject)->writeParamListToMessage(&msg);
             break;
          case OBJECT_CLUSTER:
          case OBJECT_TEMPLATE:
index 3186687..a439e43 100644 (file)
@@ -165,88 +165,63 @@ public:
 
 
 //
-// Data collection item class
+// Generic data collection object
 //
 
 class Template;
 
-class NXCORE_EXPORTABLE DCItem
+class NXCORE_EXPORTABLE DCObject
 {
-private:
+protected:
    DWORD m_dwId;
    TCHAR m_szName[MAX_ITEM_NAME];
    TCHAR m_szDescription[MAX_DB_STRING];
-   TCHAR m_szInstance[MAX_DB_STRING];
        TCHAR m_systemTag[MAX_DB_STRING];
    time_t m_tLastPoll;           // Last poll time
    int m_iPollingInterval;       // Polling interval in seconds
    int m_iRetentionTime;         // Retention time in seconds
-   BYTE m_deltaCalculation;      // Delta calculation method
-   BYTE m_source;                // SNMP or native agent?
-   BYTE m_dataType;
+   BYTE m_source;                // origin: SNMP, agent, etc.
    BYTE m_status;                // Item status: active, disabled or not supported
    BYTE m_busy;                  // 1 when item is queued for polling, 0 if not
        BYTE m_scheduledForDeletion;  // 1 when item is scheduled for deletion, 0 if not
        WORD m_flags;
    DWORD m_dwTemplateId;         // Related template's id
    DWORD m_dwTemplateItemId;     // Related template item's id
-   DWORD m_dwNumThresholds;
-   Threshold **m_ppThresholdList;
    Template *m_pNode;             // Pointer to node or template object this item related to
-   TCHAR *m_pszScript;           // Transformation script
-   NXSL_Program *m_pScript;      // Compiled transformation script
    MUTEX m_hMutex;
-   DWORD m_dwCacheSize;          // Number of items in cache
-   ItemValue **m_ppValueCache;
-   ItemValue m_prevRawValue;     // Previous raw value (used for delta calculation)
-   time_t m_tPrevValueTimeStamp;
-   BOOL m_bCacheLoaded;
    DWORD m_dwNumSchedules;
    TCHAR **m_ppScheduleList;
    time_t m_tLastCheck;          // Last schedule checking time
    DWORD m_dwErrorCount;         // Consequtive collection error count
        DWORD m_dwResourceId;           // Associated cluster resource ID
        DWORD m_dwProxyNode;          // Proxy node ID or 0 to disable
-       int m_nBaseUnits;
-       int m_nMultiplier;
-       TCHAR *m_pszCustomUnitName;
-       TCHAR *m_pszPerfTabSettings;
-       WORD m_snmpRawValueType;                // Actual SNMP raw value type for input transformation
        WORD m_snmpPort;                                        // Custom SNMP port or 0 for node default
+       TCHAR *m_pszPerfTabSettings;
 
    void lock() { MutexLock(m_hMutex); }
    void unlock() { MutexUnlock(m_hMutex); }
 
-   void transform(ItemValue &value, time_t nElapsedTime);
-   void checkThresholds(ItemValue &value);
-   void clearCache();
-
-       BOOL matchClusterResource();
+       bool matchClusterResource();
 
        void expandMacros(const TCHAR *src, TCHAR *dst, size_t dstLen);
 
-public:
-   DCItem();
-   DCItem(const DCItem *pItem);
-   DCItem(DB_RESULT hResult, int iRow, Template *pNode);
-   DCItem(DWORD dwId, const TCHAR *szName, int iSource, int iDataType, 
-          int iPollingInterval, int iRetentionTime, Template *pNode,
-          const TCHAR *pszDescription = NULL, const TCHAR *systemTag = NULL);
-       DCItem(ConfigEntry *config, Template *owner);
-   ~DCItem();
+       virtual bool isCacheLoaded();
 
-   bool prepareForDeletion();
-   void updateFromTemplate(DCItem *pItem);
+       // --- constructors ---
+   DCObject();
+   DCObject(const DCObject *src);
+   DCObject(DWORD dwId, const TCHAR *szName, int iSource, int iPollingInterval, int iRetentionTime, Template *pNode,
+            const TCHAR *pszDescription = NULL, const TCHAR *systemTag = NULL);
+       DCObject(ConfigEntry *config, Template *owner);
 
-   BOOL saveToDB(DB_HANDLE hdb);
-   BOOL loadThresholdsFromDB();
-   void deleteFromDB();
+public:
+       virtual ~DCObject();
 
-   void updateCacheSize(DWORD dwCondId = 0);
+   virtual BOOL saveToDB(DB_HANDLE hdb);
+   virtual void deleteFromDB();
 
-   DWORD getId() { return m_dwId; }
+       DWORD getId() { return m_dwId; }
    int getDataSource() { return m_source; }
-   int getDataType() { return m_dataType; }
    int getStatus() { return m_status; }
    const TCHAR *getName() { return m_szName; }
    const TCHAR *getDescription() { return m_szDescription; }
@@ -260,17 +235,90 @@ public:
        time_t getLastPollTime() { return m_tLastPoll; }
        DWORD getErrorCount() { return m_dwErrorCount; }
        WORD getSnmpPort() { return m_snmpPort; }
-       bool isInterpretSnmpRawValue() { return (m_flags & DCF_RAW_VALUE_OCTET_STRING) ? true : false; }
-       WORD getSnmpRawValueType() { return m_snmpRawValueType; }
 
    bool isReadyForPolling(time_t currTime);
        bool isScheduledForDeletion() { return m_scheduledForDeletion ? true : false; }
    void setLastPollTime(time_t tLastPoll) { m_tLastPoll = tLastPoll; }
    void setStatus(int status, bool generateEvent);
    void setBusyFlag(BOOL busy) { m_busy = (BYTE)busy; }
-   void changeBinding(DWORD dwNewId, Template *pNode, BOOL doMacroExpansion);
    void setTemplateId(DWORD dwTemplateId, DWORD dwItemId) 
          { m_dwTemplateId = dwTemplateId; m_dwTemplateItemId = dwItemId; }
+
+   virtual void createMessage(CSCPMessage *pMsg);
+   virtual void updateFromMessage(CSCPMessage *pMsg);
+
+   virtual void changeBinding(DWORD dwNewId, Template *pNode, BOOL doMacroExpansion);
+
+       virtual void deleteExpiredData();
+       virtual bool deleteAllData();
+
+   virtual void getEventList(DWORD **ppdwList, DWORD *pdwSize);
+   virtual void createNXMPRecord(String &str);
+
+       void setName(const TCHAR *pszName) { nx_strncpy(m_szName, pszName, MAX_ITEM_NAME); }
+       void setDescription(const TCHAR *pszDescr) { nx_strncpy(m_szDescription, pszDescr, MAX_DB_STRING); }
+       void setOrigin(int origin) { m_source = origin; }
+       void setRetentionTime(int nTime) { m_iRetentionTime = nTime; }
+       void setInterval(int nInt) { m_iPollingInterval = nInt; }
+       void setAdvScheduleFlag(BOOL bFlag) { if (bFlag) m_flags |= DCF_ADVANCED_SCHEDULE; else m_flags &= ~DCF_ADVANCED_SCHEDULE; }
+       void addSchedule(const TCHAR *pszSchedule);
+
+       bool prepareForDeletion();
+};
+
+
+//
+// Data collection item class
+//
+
+class NXCORE_EXPORTABLE DCItem : public DCObject
+{
+protected:
+   TCHAR m_szInstance[MAX_DB_STRING];
+   BYTE m_deltaCalculation;      // Delta calculation method
+   BYTE m_dataType;
+   DWORD m_dwNumThresholds;
+   Threshold **m_ppThresholdList;
+   TCHAR *m_pszScript;           // Transformation script
+   NXSL_Program *m_pScript;      // Compiled transformation script
+   DWORD m_dwCacheSize;          // Number of items in cache
+   ItemValue **m_ppValueCache;
+   ItemValue m_prevRawValue;     // Previous raw value (used for delta calculation)
+   time_t m_tPrevValueTimeStamp;
+   bool m_bCacheLoaded;
+       int m_nBaseUnits;
+       int m_nMultiplier;
+       TCHAR *m_pszCustomUnitName;
+       WORD m_snmpRawValueType;                // Actual SNMP raw value type for input transformation
+
+   void transform(ItemValue &value, time_t nElapsedTime);
+   void checkThresholds(ItemValue &value);
+   void clearCache();
+
+       virtual bool isCacheLoaded();
+
+public:
+   DCItem();
+   DCItem(const DCItem *pItem);
+   DCItem(DB_RESULT hResult, int iRow, Template *pNode);
+   DCItem(DWORD dwId, const TCHAR *szName, int iSource, int iDataType, 
+          int iPollingInterval, int iRetentionTime, Template *pNode,
+          const TCHAR *pszDescription = NULL, const TCHAR *systemTag = NULL);
+       DCItem(ConfigEntry *config, Template *owner);
+   virtual ~DCItem();
+
+   void updateFromTemplate(DCItem *pItem);
+
+   virtual BOOL saveToDB(DB_HANDLE hdb);
+   virtual void deleteFromDB();
+   BOOL loadThresholdsFromDB();
+
+   void updateCacheSize(DWORD dwCondId = 0);
+
+   int getDataType() { return m_dataType; }
+       bool isInterpretSnmpRawValue() { return (m_flags & DCF_RAW_VALUE_OCTET_STRING) ? true : false; }
+       WORD getSnmpRawValueType() { return m_snmpRawValueType; }
+
        void systemModify(const TCHAR *pszName, int nOrigin, int nRetention, int nInterval, int nDataType);
 
    void processNewValue(time_t nTimeStamp, const TCHAR *pszValue);
@@ -279,31 +327,26 @@ public:
    void getLastValue(CSCPMessage *pMsg, DWORD dwId);
    NXSL_Value *getValueForNXSL(int nFunction, int nPolls);
 
-   void createMessage(CSCPMessage *pMsg);
+   virtual void createMessage(CSCPMessage *pMsg);
    void updateFromMessage(CSCPMessage *pMsg, DWORD *pdwNumMaps, DWORD **ppdwMapIndex, DWORD **ppdwMapId);
        void fillMessageWithThresholds(CSCPMessage *msg);
 
-   void deleteExpiredData();
-       BOOL deleteAllData();
+   virtual void changeBinding(DWORD dwNewId, Template *pNode, BOOL doMacroExpansion);
+
+   virtual void deleteExpiredData();
+       virtual bool deleteAllData();
 
-   void getEventList(DWORD **ppdwList, DWORD *pdwSize);
-   void createNXMPRecord(String &str);
+   virtual void getEventList(DWORD **ppdwList, DWORD *pdwSize);
+   virtual void createNXMPRecord(String &str);
 
        BOOL enumThresholds(BOOL (* pfCallback)(Threshold *, DWORD, void *), void *pArg);
 
-       void setName(const TCHAR *pszName) { nx_strncpy(m_szName, pszName, MAX_ITEM_NAME); }
-       void setDescription(const TCHAR *pszDescr) { nx_strncpy(m_szDescription, pszDescr, MAX_DB_STRING); }
        void setInstance(const TCHAR *pszInstance) { nx_strncpy(m_szInstance, pszInstance, MAX_DB_STRING); }
-       void setOrigin(int origin) { m_source = origin; }
        void setDataType(int dataType) { m_dataType = dataType; }
-       void setRetentionTime(int nTime) { m_iRetentionTime = nTime; }
-       void setInterval(int nInt) { m_iPollingInterval = nInt; }
        void setDeltaCalcMethod(int method) { m_deltaCalculation = method; }
        void setAllThresholdsFlag(BOOL bFlag) { if (bFlag) m_flags |= DCF_ALL_THRESHOLDS; else m_flags &= ~DCF_ALL_THRESHOLDS; }
-       void setAdvScheduleFlag(BOOL bFlag) { if (bFlag) m_flags |= DCF_ADVANCED_SCHEDULE; else m_flags &= ~DCF_ADVANCED_SCHEDULE; }
        void addThreshold(Threshold *pThreshold);
        void deleteAllThresholds();
-       void addSchedule(const TCHAR *pszSchedule);
    void setTransformationScript(const TCHAR *pszScript);
 
        BOOL testTransformation(const TCHAR *script, const TCHAR *value, TCHAR *buffer, size_t bufSize);
index 2e27b4d..e22b375 100644 (file)
@@ -563,19 +563,19 @@ public:
 
    virtual void calculateCompoundStatus(BOOL bForcedRecalc = FALSE);
 
-       BOOL isSyncAddr(DWORD dwAddr);
-       BOOL isVirtualAddr(DWORD dwAddr);
-       BOOL isResourceOnNode(DWORD dwResource, DWORD dwNode);
+       bool isSyncAddr(DWORD dwAddr);
+       bool isVirtualAddr(DWORD dwAddr);
+       bool isResourceOnNode(DWORD dwResource, DWORD dwNode);
    DWORD getZoneId() { return m_zoneId; }
 
    void statusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller);
    void lockForStatusPoll() { m_dwFlags |= CLF_QUEUED_FOR_STATUS_POLL; }
-   BOOL isReadyForStatusPoll() 
+   bool isReadyForStatusPoll() 
    {
       return ((m_iStatus != STATUS_UNMANAGED) && (!m_bIsDeleted) &&
               (!(m_dwFlags & CLF_QUEUED_FOR_STATUS_POLL)) &&
               ((DWORD)time(NULL) - (DWORD)m_tmLastPoll > g_dwStatusPollingInterval))
-                  ? TRUE : FALSE;
+                  ? true : false;
    }
 };
 
@@ -773,8 +773,8 @@ protected:
        TCHAR *m_sysName;                               // SNMP sysName
        TCHAR *m_lldpNodeId;                    // lldpLocChassisId combined with lldpLocChassisIdSubtype, or NULL for non-LLDP nodes
        NetworkDeviceDriver *m_driver;
-   DWORD m_dwNumParams;           // Number of elements in supported parameters list
-   NXC_AGENT_PARAM *m_pParamList; // List of supported parameters
+   StructArray<NXC_AGENT_PARAM> *m_paramList; // List of supported parameters
+   StructArray<NXC_AGENT_TABLE> *m_tableList; // List of supported tables
    time_t m_tLastDiscoveryPoll;
    time_t m_tLastStatusPoll;
    time_t m_tLastConfigurationPoll;
@@ -945,7 +945,7 @@ public:
 
        bool checkAgentTrapId(QWORD id);
 
-   void openParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList);
+   void openParamList(StructArray<NXC_AGENT_PARAM> **paramList);
    void closeParamList() { UnlockData(); }
 
    AgentConnectionEx *createAgentConnection();
@@ -954,7 +954,7 @@ public:
 
    virtual void CreateMessage(CSCPMessage *pMsg);
    virtual DWORD ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked = FALSE);
-   void WriteParamListToMessage(CSCPMessage *pMsg);
+   void writeParamListToMessage(CSCPMessage *pMsg);
 
    DWORD wakeUp();
 
index b26ac8c..9f1b81a 100644 (file)
@@ -456,7 +456,7 @@ public:
    DWORD startUpgrade(const TCHAR *pszPkgName);
    DWORD checkNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType, WORD wPort = 0, 
                              WORD wProto = 0, const TCHAR *pszRequest = NULL, const TCHAR *pszResponse = NULL);
-   DWORD getSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList);
+   DWORD getSupportedParameters(StructArray<NXC_AGENT_PARAM> **paramList, StructArray<NXC_AGENT_TABLE> **tableList);
    DWORD getConfigFile(TCHAR **ppszConfig, DWORD *pdwSize);
    DWORD updateConfigFile(const TCHAR *pszConfig);
    DWORD enableTraps();
index 8b64c40..6da41a6 100644 (file)
@@ -1,7 +1,7 @@
 /* 
 ** NetXMS - Network Management System
 ** Server Library
-** Copyright (C) 2003-2011 Victor Kirhenshtein
+** Copyright (C) 2003-2012 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU Lesser General Public License as published by
@@ -1181,13 +1181,13 @@ DWORD AgentConnection::checkNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int
 // Get list of supported parameters from subagent
 //
 
-DWORD AgentConnection::getSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
+DWORD AgentConnection::getSupportedParameters(StructArray<NXC_AGENT_PARAM> **paramList, StructArray<NXC_AGENT_TABLE> **tableList)
 {
-   DWORD i, dwId, dwRqId, dwResult;
+   DWORD dwRqId, dwResult;
    CSCPMessage msg(m_nProtocolVersion), *pResponse;
 
-   *pdwNumParams = 0;
-   *ppParamList = NULL;
+   *paramList = NULL;
+       *tableList = NULL;
 
    if (!m_bIsConnected)
       return ERR_NOT_CONNECTED;
@@ -1203,19 +1203,31 @@ DWORD AgentConnection::getSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PAR
       if (pResponse != NULL)
       {
          dwResult = pResponse->GetVariableLong(VID_RCC);
-                       DbgPrintf(6, _T("AgentConnection::GetSupportedParameters(): RCC=%d"), dwResult);
+                       DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
          if (dwResult == ERR_SUCCESS)
          {
-            *pdwNumParams = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
-            *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * (*pdwNumParams));
-            for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
+            DWORD count = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
+            NXC_AGENT_PARAM *plist = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * count);
+            for(DWORD i = 0, dwId = VID_PARAM_LIST_BASE; i < count; i++)
             {
-               pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
-               pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
-               (*ppParamList)[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
+               pResponse->GetVariableStr(dwId++, plist[i].szName, MAX_PARAM_NAME);
+               pResponse->GetVariableStr(dwId++, plist[i].szDescription, MAX_DB_STRING);
+               plist[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
             }
-                               DbgPrintf(6, _T("AgentConnection::GetSupportedParameters(): %d parameters received from agent"), *pdwNumParams);
-         }
+                               *paramList = new StructArray<NXC_AGENT_PARAM>(plist, (int)count);
+                               DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
+
+            count = pResponse->GetVariableLong(VID_NUM_TABLES);
+            NXC_AGENT_TABLE *tlist = (NXC_AGENT_TABLE *)malloc(sizeof(NXC_AGENT_TABLE) * count);
+            for(DWORD i = 0, dwId = VID_TABLE_LIST_BASE; i < count; i++)
+            {
+               pResponse->GetVariableStr(dwId++, tlist[i].name, MAX_PARAM_NAME);
+               pResponse->GetVariableStr(dwId++, tlist[i].instanceColumn, MAX_DB_STRING);
+               pResponse->GetVariableStr(dwId++, tlist[i].description, MAX_DB_STRING);
+            }
+                               *tableList = new StructArray<NXC_AGENT_TABLE>(tlist, (int)count);
+                               DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
+                       }
          delete pResponse;
       }
       else
index edb82d3..f0c04b2 100644 (file)
@@ -277,6 +277,45 @@ static BOOL CreateEventTemplate(int code, const TCHAR *name, int severity, int f
 }
 
 
+//
+// Upgrade from V247 to V248
+//
+
+static BOOL H_UpgradeFromV247(int currVersion, int newVersion)
+{
+       CHK_EXEC(CreateTable(_T("CREATE TABLE dc_tables (")
+                            _T("item_id integer not null,")
+                                                               _T("node_id integer not null,")
+                                                               _T("template_id integer not null,")
+                                                               _T("template_item_id integer not null,")
+                                                               _T("name varchar(255) null,")
+                                                               _T("instance_column varchar(63) null,")
+                                                               _T("description varchar(255) null,")
+                                                               _T("flags integer not null,")
+                                                               _T("source integer not null,")
+                                                               _T("snmp_port integer not null,")
+                                                               _T("polling_interval integer not null,")
+                                                               _T("retention_time integer not null,")
+                                                               _T("status integer not null,")
+                                                               _T("system_tag varchar(255) null,")
+                                                               _T("resource_id integer not null,")
+                                                               _T("proxy_node integer not null,")
+                                                               _T("perftab_settings $SQL:TEXT null,")
+                            _T("PRIMARY KEY(item_id))")));
+
+       CHK_EXEC(CreateTable(_T("CREATE TABLE dc_table_columns (")
+                            _T("table_id integer not null,")
+                            _T("column_name varchar(63) not null,")
+                                                               _T("snmp_oid varchar(1023) null,")
+                                                               _T("data_type integer not null,")
+                                                               _T("transformation_script $SQL:TEXT null,")
+                            _T("PRIMARY KEY(table_id,column_name))")));
+
+       CHK_EXEC(SQLQuery(_T("UPDATE metadata SET var_value='248' WHERE var_name='SchemaVersion'")));
+   return TRUE;
+}
+
+
 //
 // Upgrade from V246 to V247
 //
@@ -5997,6 +6036,7 @@ static struct
        { 244, 245, H_UpgradeFromV244 },
        { 245, 246, H_UpgradeFromV245 },
        { 246, 247, H_UpgradeFromV246 },
+       { 247, 248, H_UpgradeFromV247 },
    { 0, 0, NULL }
 };
 
index c153b98..73a3d6b 100644 (file)
@@ -161,20 +161,22 @@ static int CheckService(AgentConnection *pConn, int iServiceType, DWORD dwServic
 
 static int ListParameters(AgentConnection *pConn)
 {
-   DWORD i, dwNumParams, dwError;
-   NXC_AGENT_PARAM *pParamList;
    static const TCHAR *pszDataType[] = { _T("INT"), _T("UINT"), _T("INT64"), _T("UINT64"), _T("STRING"), _T("FLOAT"), _T("UNKNOWN") };
 
-   dwError = pConn->getSupportedParameters(&dwNumParams, &pParamList);
+   StructArray<NXC_AGENT_PARAM> *paramList;
+   StructArray<NXC_AGENT_TABLE> *tableList;
+   DWORD dwError = pConn->getSupportedParameters(&paramList, &tableList);
    if (dwError == ERR_SUCCESS)
    {
-      for(i = 0; i < dwNumParams; i++)
+      for(int i = 0; i < paramList->size(); i++)
       {
-         _tprintf(_T("%s %s \"%s\"\n"), pParamList[i].szName,
-            pszDataType[(pParamList[i].iDataType < 6) && (pParamList[i].iDataType >= 0) ? pParamList[i].iDataType : 6],
-            pParamList[i].szDescription);
+                       NXC_AGENT_PARAM *p = paramList->get(i);
+         _tprintf(_T("%s %s \"%s\"\n"), p->szName,
+            pszDataType[(p->iDataType < 6) && (p->iDataType >= 0) ? p->iDataType : 6],
+            p->szDescription);
       }
-      safe_free(pParamList);
+      delete paramList;
+               delete tableList;
    }
    else
    {
diff --git a/tools/chkmsgs.sh b/tools/chkmsgs.sh
new file mode 100755 (executable)
index 0000000..ca3875f
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+usage() {
+       echo "usage `basename $0` <dir> <lang> <verbose>";
+       echo "dir: netxms source directory"
+       echo "lang: two-letter abbreviation";
+       echo "verbose: on|off "
+}
+
+compare() {
+       local _dir="$1"
+       local _lang="$2"
+       local _verb="$3"
+       local _name="$4" 
+       
+       for MFILE in `find "$_dir" -name "$_name" -print`; do
+               BASENAME=`basename $MFILE`              
+               PREFIX="${BASENAME%.properties}"
+               DIR=`dirname $MFILE`
+               LFILE=$DIR/$PREFIX"_$_lang.properties"
+               if [ -f $LFILE ]; then
+                       LINES_M=`wc -l < $MFILE | tr -d '\n'`
+                       LINES_L=`wc -l < $LFILE | tr -d '\n'`
+                       if [ "$LINES_M" != "$LINES_L" ]; then
+                               echo "$DIR [$LINES_M:$LINES_L] ! $LFILE"
+                       else
+                               if [ "$_verb" == "on" ]; then
+                                       echo "$DIR [$LINES_M:$LINES_L]"
+                               fi
+                       fi
+               else
+                       echo "can't find $LFILE"
+               fi
+       done
+}
+
+if [ $# -lt 2 ]; then
+       usage
+       exit
+fi
+
+if [  $# -eq 3 ]; then
+       case "$3" in
+       on)
+               VERB="$3"
+               ;;
+       off)
+               VERB="$3"
+               ;;
+       *)
+               usage
+               exit
+               ;;
+       esac
+else
+       usage
+       exit
+fi 
+
+for F in messages bundle compare ; do
+       compare "$1" "$2" "$VERB" "$F.properties"
+done