"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/server/core/netmap.cpp" (23 Feb 2021, 36681 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "netmap.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.7.130_vs_3.7.145.

    1 /*
    2 ** NetXMS - Network Management System
    3 ** Copyright (C) 2003-2021 Raden Solutions
    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: netmap.cpp
   20 **
   21 **/
   22 
   23 #include "nxcore.h"
   24 
   25 #define DEBUG_TAG_NETMAP   _T("obj.netmap")
   26 
   27 /**
   28  * Redefined status calculation for network maps group
   29  */
   30 void NetworkMapGroup::calculateCompoundStatus(BOOL bForcedRecalc)
   31 {
   32    m_status = STATUS_NORMAL;
   33 }
   34 
   35 /**
   36  * Called by client session handler to check if threshold summary should be shown for this object.
   37  */
   38 bool NetworkMapGroup::showThresholdSummary() const
   39 {
   40     return false;
   41 }
   42 
   43 /**
   44  * Network map object default constructor
   45  */
   46 NetworkMap::NetworkMap() : super()
   47 {
   48     m_mapType = NETMAP_USER_DEFINED;
   49     m_discoveryRadius = -1;
   50     m_flags = MF_SHOW_STATUS_ICON;
   51     m_layout = MAP_LAYOUT_MANUAL;
   52     m_status = STATUS_NORMAL;
   53     m_backgroundLatitude = 0;
   54     m_backgroundLongitude = 0;
   55     m_backgroundZoom = 1;
   56     m_backgroundColor = ConfigReadInt(_T("DefaultMapBackgroundColor"), 0xFFFFFF);
   57     m_defaultLinkColor = -1;
   58    m_defaultLinkRouting = 1;  // default routing type "direct"
   59    m_objectDisplayMode = 0;  // default display mode "icons"
   60     m_nextElementId = 1;
   61     m_elements = new ObjectArray<NetworkMapElement>(0, 32, Ownership::True);
   62     m_links = new ObjectArray<NetworkMapLink>(0, 32, Ownership::True);
   63    m_filterSource = nullptr;
   64    m_filter = nullptr;
   65    m_seedObjects = new IntegerArray<UINT32>();
   66 }
   67 
   68 /**
   69  * Create network map object from user session
   70  */
   71 NetworkMap::NetworkMap(int type, IntegerArray<UINT32> *seeds) : super()
   72 {
   73     m_mapType = type;
   74     if (type == MAP_INTERNAL_COMMUNICATION_TOPOLOGY)
   75     {
   76        m_seedObjects = new IntegerArray<UINT32>();
   77        m_seedObjects->add(FindLocalMgmtNode());
   78     }
   79     else
   80        m_seedObjects = new IntegerArray<UINT32>(seeds);
   81     m_discoveryRadius = -1;
   82     m_flags = MF_SHOW_STATUS_ICON;
   83    m_layout = (type == NETMAP_USER_DEFINED) ? MAP_LAYOUT_MANUAL : MAP_LAYOUT_SPRING;
   84     m_status = STATUS_NORMAL;
   85     m_backgroundLatitude = 0;
   86     m_backgroundLongitude = 0;
   87     m_backgroundZoom = 1;
   88     m_backgroundColor = ConfigReadInt(_T("DefaultMapBackgroundColor"), 0xFFFFFF);
   89     m_defaultLinkColor = -1;
   90    m_defaultLinkRouting = 1;  // default routing type "direct"
   91    m_objectDisplayMode = 0;  // default display mode "icons"
   92     m_nextElementId = 1;
   93     m_elements = new ObjectArray<NetworkMapElement>(0, 32, Ownership::True);
   94     m_links = new ObjectArray<NetworkMapLink>(0, 32, Ownership::True);
   95    m_filterSource = nullptr;
   96    m_filter = nullptr;
   97     m_isHidden = true;
   98    setCreationTime();
   99 
  100 }
  101 
  102 /**
  103  * Network map object destructor
  104  */
  105 NetworkMap::~NetworkMap()
  106 {
  107     delete m_elements;
  108     delete m_links;
  109    delete m_filter;
  110    delete m_seedObjects;
  111    MemFree(m_filterSource);
  112 }
  113 
  114 /**
  115  * Redefined status calculation for network maps
  116  */
  117 void NetworkMap::calculateCompoundStatus(BOOL bForcedRecalc)
  118 {
  119    if (m_flags & MF_CALCULATE_STATUS)
  120    {
  121       if (m_status != STATUS_UNMANAGED)
  122       {
  123          int iMostCriticalStatus, iCount, iStatusAlg;
  124          int nSingleThreshold, *pnThresholds, iOldStatus = m_status;
  125          int nRating[5], iChildStatus, nThresholds[4];
  126 
  127          lockProperties();
  128          if (m_statusCalcAlg == SA_CALCULATE_DEFAULT)
  129          {
  130             iStatusAlg = GetDefaultStatusCalculation(&nSingleThreshold, &pnThresholds);
  131          }
  132          else
  133          {
  134             iStatusAlg = m_statusCalcAlg;
  135             nSingleThreshold = m_statusSingleThreshold;
  136             pnThresholds = m_statusThresholds;
  137          }
  138          if (iStatusAlg == SA_CALCULATE_SINGLE_THRESHOLD)
  139          {
  140             for(int i = 0; i < 4; i++)
  141                nThresholds[i] = nSingleThreshold;
  142             pnThresholds = nThresholds;
  143          }
  144 
  145          switch(iStatusAlg)
  146          {
  147             case SA_CALCULATE_MOST_CRITICAL:
  148                iCount = 0;
  149                iMostCriticalStatus = -1;
  150                for(int i = 0; i < m_elements->size(); i++)
  151                {
  152                   NetworkMapElement *e = m_elements->get(i);
  153                   if (e->getType() != MAP_ELEMENT_OBJECT)
  154                      continue;
  155 
  156                   shared_ptr<NetObj> object = FindObjectById(((NetworkMapObject *)e)->getObjectId());
  157                   if (object == nullptr)
  158                      continue;
  159 
  160                   iChildStatus = object->getPropagatedStatus();
  161                   if ((iChildStatus < STATUS_UNKNOWN) &&
  162                       (iChildStatus > iMostCriticalStatus))
  163                   {
  164                      iMostCriticalStatus = iChildStatus;
  165                      iCount++;
  166                   }
  167                }
  168                m_status = (iCount > 0) ? iMostCriticalStatus : STATUS_NORMAL;
  169                break;
  170             case SA_CALCULATE_SINGLE_THRESHOLD:
  171             case SA_CALCULATE_MULTIPLE_THRESHOLDS:
  172                // Step 1: calculate severity ratings
  173                memset(nRating, 0, sizeof(int) * 5);
  174                iCount = 0;
  175                for(int i = 0; i < m_elements->size(); i++)
  176                {
  177                   NetworkMapElement *e = m_elements->get(i);
  178                   if (e->getType() != MAP_ELEMENT_OBJECT)
  179                      continue;
  180 
  181                   shared_ptr<NetObj> object = FindObjectById(((NetworkMapObject *)e)->getObjectId());
  182                   if (object == nullptr)
  183                      continue;
  184 
  185                   iChildStatus = object->getPropagatedStatus();
  186                   if (iChildStatus < STATUS_UNKNOWN)
  187                   {
  188                      while(iChildStatus >= 0)
  189                         nRating[iChildStatus--]++;
  190                      iCount++;
  191                   }
  192                }
  193 
  194                // Step 2: check what severity rating is above threshold
  195                if (iCount > 0)
  196                {
  197                   int i;
  198                   for(i = 4; i > 0; i--)
  199                      if (nRating[i] * 100 / iCount >= pnThresholds[i - 1])
  200                         break;
  201                   m_status = i;
  202                }
  203                else
  204                {
  205                   m_status = STATUS_NORMAL;
  206                }
  207                break;
  208             default:
  209                m_status = STATUS_NORMAL;
  210                break;
  211          }
  212          unlockProperties();
  213 
  214          // Cause parent object(s) to recalculate it's status
  215          if ((iOldStatus != m_status) || bForcedRecalc)
  216          {
  217             readLockParentList();
  218             for(int i = 0; i < getParentList().size(); i++)
  219                getParentList().get(i)->calculateCompoundStatus();
  220             unlockParentList();
  221             lockProperties();
  222             setModified(MODIFY_RUNTIME);
  223             unlockProperties();
  224          }
  225       }
  226    }
  227    else
  228    {
  229       if (m_status != STATUS_NORMAL && m_status != STATUS_UNMANAGED)
  230       {
  231          m_status = STATUS_NORMAL;
  232          readLockParentList();
  233          for(int i = 0; i < getParentList().size(); i++)
  234             getParentList().get(i)->calculateCompoundStatus();
  235          unlockParentList();
  236          lockProperties();
  237          setModified(MODIFY_RUNTIME);
  238          unlockProperties();
  239       }
  240    }
  241 }
  242 
  243 /**
  244  * Save to database
  245  */
  246 bool NetworkMap::saveToDatabase(DB_HANDLE hdb)
  247 {
  248    bool success = super::saveToDatabase(hdb);
  249 
  250    if (success && (m_modified & MODIFY_OTHER))
  251    {
  252       DB_STATEMENT hStmt;
  253       if (IsDatabaseRecordExist(hdb, _T("network_maps"), _T("id"), m_id))
  254       {
  255          hStmt = DBPrepare(hdb, _T("UPDATE network_maps SET map_type=?,layout=?,radius=?,background=?,bg_latitude=?,bg_longitude=?,bg_zoom=?,link_color=?,link_routing=?,bg_color=?,object_display_mode=?,filter=? WHERE id=?"));
  256       }
  257       else
  258       {
  259          hStmt = DBPrepare(hdb, _T("INSERT INTO network_maps (map_type,layout,radius,background,bg_latitude,bg_longitude,bg_zoom,link_color,link_routing,bg_color,object_display_mode,filter,id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
  260       }
  261       if (hStmt != nullptr)
  262       {
  263          lockProperties();
  264 
  265          DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (INT32)m_mapType);
  266          DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (INT32)m_layout);
  267          DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (INT32)m_discoveryRadius);
  268          DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, m_background);
  269          DBBind(hStmt, 5, DB_SQLTYPE_DOUBLE, m_backgroundLatitude);
  270          DBBind(hStmt, 6, DB_SQLTYPE_DOUBLE, m_backgroundLongitude);
  271          DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (INT32)m_backgroundZoom);
  272          DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (INT32)m_defaultLinkColor);
  273          DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (INT32)m_defaultLinkRouting);
  274          DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, (INT32)m_backgroundColor);
  275          DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, (INT32)m_objectDisplayMode);
  276          DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_filterSource, DB_BIND_STATIC);
  277          DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, m_id);
  278 
  279          success = DBExecute(hStmt);
  280          DBFreeStatement(hStmt);
  281 
  282          unlockProperties();
  283       }
  284       else
  285       {
  286          success = false;
  287       }
  288    }
  289 
  290    // Save elements
  291    if (success && (m_modified & MODIFY_MAP_CONTENT))
  292    {
  293       success = executeQueryOnObject(hdb, _T("DELETE FROM network_map_elements WHERE map_id=?"));
  294 
  295       lockProperties();
  296       if (success && !m_elements->isEmpty())
  297       {
  298          DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO network_map_elements (map_id,element_id,element_type,element_data,flags) VALUES (?,?,?,?,?)"));
  299          if (hStmt != nullptr)
  300          {
  301             DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
  302             for(int i = 0; success && (i < m_elements->size()); i++)
  303             {
  304                NetworkMapElement *e = m_elements->get(i);
  305                Config *config = new Config();
  306                config->setTopLevelTag(_T("element"));
  307                e->updateConfig(config);
  308 
  309                DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, e->getId());
  310                DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, e->getType());
  311                DBBind(hStmt, 4, DB_SQLTYPE_TEXT, config->createXml(), DB_BIND_TRANSIENT);
  312                DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, e->getFlags());
  313 
  314                success = DBExecute(hStmt);
  315                delete config;
  316             }
  317             DBFreeStatement(hStmt);
  318          }
  319          else
  320          {
  321             success = false;
  322          }
  323       }
  324       unlockProperties();
  325 
  326       // Save links
  327       if (success)
  328          success = executeQueryOnObject(hdb, _T("DELETE FROM network_map_links WHERE map_id=?"));
  329 
  330       lockProperties();
  331       if (success && !m_links->isEmpty())
  332       {
  333          DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO network_map_links (map_id,element1,element2,link_type,link_name,connector_name1,connector_name2,element_data,flags) VALUES (?,?,?,?,?,?,?,?,?)"));
  334          if (hStmt != nullptr)
  335          {
  336             DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
  337             for(int i = 0; success && (i < m_links->size()); i++)
  338             {
  339                NetworkMapLink *l = m_links->get(i);
  340                DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, l->getElement1());
  341                DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, l->getElement2());
  342                DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (LONG)l->getType());
  343                DBBind(hStmt, 5, DB_SQLTYPE_VARCHAR, l->getName(), DB_BIND_STATIC);
  344                DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, l->getConnector1Name(), DB_BIND_STATIC);
  345                DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, l->getConnector2Name(), DB_BIND_STATIC);
  346                DBBind(hStmt, 8, DB_SQLTYPE_VARCHAR, l->getConfig(), DB_BIND_STATIC);
  347                DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, l->getFlags());
  348                success = DBExecute(hStmt);
  349             }
  350             DBFreeStatement(hStmt);
  351          }
  352          else
  353          {
  354             success = false;
  355          }
  356       }
  357       unlockProperties();
  358    }
  359 
  360     // Save seed nodes
  361    if (success && (m_modified & MODIFY_OTHER))
  362    {
  363       success = executeQueryOnObject(hdb, _T("DELETE FROM network_map_seed_nodes WHERE map_id=?"));
  364 
  365       lockProperties();
  366       if (success && (m_seedObjects->size() > 0))
  367       {
  368          DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO network_map_seed_nodes (map_id,seed_node_id) VALUES (?,?)"));
  369          if (hStmt != nullptr)
  370          {
  371             DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
  372             for(int i = 0; success && (i < m_seedObjects->size()); i++)
  373             {
  374                DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_seedObjects->get(i));
  375                success = DBExecute(hStmt);
  376             }
  377             DBFreeStatement(hStmt);
  378          }
  379          else
  380          {
  381             success = false;
  382          }
  383       }
  384       unlockProperties();
  385    }
  386 
  387     return success;
  388 }
  389 
  390 /**
  391  * Delete from database
  392  */
  393 bool NetworkMap::deleteFromDatabase(DB_HANDLE hdb)
  394 {
  395    bool success = super::deleteFromDatabase(hdb);
  396    if (success)
  397       success = executeQueryOnObject(hdb, _T("DELETE FROM network_maps WHERE id=?"));
  398    if (success)
  399       success = executeQueryOnObject(hdb, _T("DELETE FROM network_map_elements WHERE map_id=?"));
  400    if (success)
  401       success = executeQueryOnObject(hdb, _T("DELETE FROM network_map_links WHERE map_id=?"));
  402    if (success)
  403       success = executeQueryOnObject(hdb, _T("DELETE FROM network_map_seed_nodes WHERE map_id=?"));
  404    return success;
  405 }
  406 
  407 /**
  408  * Load from database
  409  */
  410 bool NetworkMap::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
  411 {
  412     m_id = dwId;
  413 
  414     if (!loadCommonProperties(hdb))
  415    {
  416       DbgPrintf(2, _T("Cannot load common properties for network map object %d"), dwId);
  417       return false;
  418    }
  419 
  420    if (!m_isDeleted)
  421    {
  422         TCHAR query[256];
  423 
  424        loadACLFromDB(hdb);
  425 
  426         _sntprintf(query, 256, _T("SELECT map_type,layout,radius,background,bg_latitude,bg_longitude,bg_zoom,link_color,link_routing,bg_color,object_display_mode,filter FROM network_maps WHERE id=%d"), dwId);
  427         DB_RESULT hResult = DBSelect(hdb, query);
  428         if (hResult == nullptr)
  429             return false;
  430 
  431         m_mapType = DBGetFieldLong(hResult, 0, 0);
  432         m_layout = DBGetFieldLong(hResult, 0, 1);
  433         m_discoveryRadius = DBGetFieldLong(hResult, 0, 2);
  434         m_background = DBGetFieldGUID(hResult, 0, 3);
  435         m_backgroundLatitude = DBGetFieldDouble(hResult, 0, 4);
  436         m_backgroundLongitude = DBGetFieldDouble(hResult, 0, 5);
  437         m_backgroundZoom = (int)DBGetFieldLong(hResult, 0, 6);
  438         m_defaultLinkColor = DBGetFieldLong(hResult, 0, 7);
  439         m_defaultLinkRouting = DBGetFieldLong(hResult, 0, 8);
  440         m_backgroundColor = DBGetFieldLong(hResult, 0, 9);
  441         m_objectDisplayMode = DBGetFieldLong(hResult, 0, 10);
  442 
  443       TCHAR *filter = DBGetField(hResult, 0, 11, nullptr, 0);
  444       setFilter(filter);
  445       MemFree(filter);
  446 
  447       DBFreeResult(hResult);
  448 
  449        // Load elements
  450       _sntprintf(query, 256, _T("SELECT element_id,element_type,element_data,flags FROM network_map_elements WHERE map_id=%d"), m_id);
  451       hResult = DBSelect(hdb, query);
  452       if (hResult != nullptr)
  453       {
  454          int count = DBGetNumRows(hResult);
  455             for(int i = 0; i < count; i++)
  456             {
  457                 NetworkMapElement *e;
  458                 UINT32 id = DBGetFieldULong(hResult, i, 0);
  459                 UINT32 flags = DBGetFieldULong(hResult, i, 3);
  460                 Config *config = new Config();
  461                 TCHAR *data = DBGetField(hResult, i, 2, nullptr, 0);
  462                 if (data != nullptr)
  463                 {
  464 #ifdef UNICODE
  465                     char *utf8data = UTF8StringFromWideString(data);
  466                     config->loadXmlConfigFromMemory(utf8data, (int)strlen(utf8data), _T("<database>"), "element");
  467                     free(utf8data);
  468 #else
  469                     config->loadXmlConfigFromMemory(data, (int)strlen(data), _T("<database>"), "element");
  470 #endif
  471                     free(data);
  472                     switch(DBGetFieldLong(hResult, i, 1))
  473                     {
  474                         case MAP_ELEMENT_OBJECT:
  475                             e = new NetworkMapObject(id, config, flags);
  476                             break;
  477                         case MAP_ELEMENT_DECORATION:
  478                             e = new NetworkMapDecoration(id, config, flags);
  479                             break;
  480                   case MAP_ELEMENT_DCI_CONTAINER:
  481                      e = new NetworkMapDCIContainer(id, config, flags);
  482                      break;
  483                   case MAP_ELEMENT_DCI_IMAGE:
  484                      e = new NetworkMapDCIImage(id, config, flags);
  485                      break;
  486                   case MAP_ELEMENT_TEXT_BOX:
  487                      e = new NetworkMapTextBox(id, config, flags);
  488                      break;
  489                         default:        // Unknown type, create generic element
  490                             e = new NetworkMapElement(id, config, flags);
  491                             break;
  492                     }
  493                 }
  494                 else
  495                 {
  496                     e = new NetworkMapElement(id, flags);
  497                 }
  498                 delete config;
  499                 m_elements->add(e);
  500                 if (m_nextElementId <= e->getId())
  501                     m_nextElementId = e->getId() + 1;
  502             }
  503          DBFreeResult(hResult);
  504       }
  505 
  506         // Load links
  507       _sntprintf(query, 256, _T("SELECT element1,element2,link_type,link_name,connector_name1,connector_name2,element_data,flags FROM network_map_links WHERE map_id=%d"), m_id);
  508       hResult = DBSelect(hdb, query);
  509       if (hResult != nullptr)
  510       {
  511          int count = DBGetNumRows(hResult);
  512             for(int i = 0; i < count; i++)
  513             {
  514                 TCHAR buffer[4096];
  515 
  516                 NetworkMapLink *l = new NetworkMapLink(DBGetFieldLong(hResult, i, 0), DBGetFieldLong(hResult, i, 1), DBGetFieldLong(hResult, i, 2));
  517                 l->setName(DBGetField(hResult, i, 3, buffer, 256));
  518                 l->setConnector1Name(DBGetField(hResult, i, 4, buffer, 256));
  519                 l->setConnector2Name(DBGetField(hResult, i, 5, buffer, 256));
  520                 l->setConfig(DBGetField(hResult, i, 6, buffer, 4096));
  521                 l->setFlags(DBGetFieldULong(hResult, i, 7));
  522                 m_links->add(l);
  523             }
  524          DBFreeResult(hResult);
  525       }
  526 
  527       // Load seed nodes
  528       DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT seed_node_id FROM network_map_seed_nodes WHERE map_id=?"));
  529       if (hStmt != nullptr)
  530       {
  531          DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
  532          hResult = DBSelectPrepared(hStmt);
  533          if (hResult != nullptr)
  534          {
  535             int nRows = DBGetNumRows(hResult);
  536             for(int i = 0; i < nRows; i++)
  537             {
  538                m_seedObjects->add(DBGetFieldULong(hResult, i, 0));
  539             }
  540             DBFreeResult(hResult);
  541          }
  542       }
  543       DBFreeStatement(hStmt);
  544     }
  545 
  546     m_status = STATUS_NORMAL;
  547 
  548     return true;
  549 }
  550 
  551 /**
  552  * Fill NXCP message with object's data
  553  */
  554 void NetworkMap::fillMessageInternal(NXCPMessage *msg, UINT32 userId)
  555 {
  556     super::fillMessageInternal(msg, userId);
  557 
  558     msg->setField(VID_MAP_TYPE, (WORD)m_mapType);
  559     msg->setField(VID_LAYOUT, (WORD)m_layout);
  560     msg->setFieldFromInt32Array(VID_SEED_OBJECTS, m_seedObjects);
  561     msg->setField(VID_DISCOVERY_RADIUS, (UINT32)m_discoveryRadius);
  562     msg->setField(VID_BACKGROUND, m_background);
  563     msg->setField(VID_BACKGROUND_LATITUDE, m_backgroundLatitude);
  564     msg->setField(VID_BACKGROUND_LONGITUDE, m_backgroundLongitude);
  565     msg->setField(VID_BACKGROUND_ZOOM, (WORD)m_backgroundZoom);
  566     msg->setField(VID_LINK_COLOR, (UINT32)m_defaultLinkColor);
  567     msg->setField(VID_LINK_ROUTING, (INT16)m_defaultLinkRouting);
  568     msg->setField(VID_DISPLAY_MODE, (INT16)m_objectDisplayMode);
  569     msg->setField(VID_BACKGROUND_COLOR, (UINT32)m_backgroundColor);
  570    msg->setField(VID_FILTER, CHECK_NULL_EX(m_filterSource));
  571 
  572     msg->setField(VID_NUM_ELEMENTS, (UINT32)m_elements->size());
  573     UINT32 varId = VID_ELEMENT_LIST_BASE;
  574     for(int i = 0; i < m_elements->size(); i++)
  575     {
  576         m_elements->get(i)->fillMessage(msg, varId);
  577         varId += 100;
  578     }
  579 
  580     msg->setField(VID_NUM_LINKS, (UINT32)m_links->size());
  581     varId = VID_LINK_LIST_BASE;
  582     for(int i = 0; i < m_links->size(); i++)
  583     {
  584         m_links->get(i)->fillMessage(msg, varId);
  585         varId += 20;
  586     }
  587 }
  588 
  589 /**
  590  * Update network map object from NXCP message
  591  */
  592 UINT32 NetworkMap::modifyFromMessageInternal(NXCPMessage *request)
  593 {
  594     if (request->isFieldExist(VID_MAP_TYPE))
  595         m_mapType = (int)request->getFieldAsUInt16(VID_MAP_TYPE);
  596 
  597     if (request->isFieldExist(VID_LAYOUT))
  598         m_layout = (int)request->getFieldAsUInt16(VID_LAYOUT);
  599 
  600     if (request->isFieldExist(VID_FLAGS))
  601     {
  602        UINT32 mask = request->isFieldExist(VID_FLAGS_MASK) ? request->getFieldAsUInt32(VID_FLAGS_MASK) : 0xFFFFFFFF;
  603        m_flags &= ~mask;
  604         m_flags |= (request->getFieldAsUInt32(VID_FLAGS) & mask);
  605     }
  606 
  607     if (request->isFieldExist(VID_SEED_OBJECTS))
  608         request->getFieldAsInt32Array(VID_SEED_OBJECTS, m_seedObjects);
  609 
  610     if (request->isFieldExist(VID_DISCOVERY_RADIUS))
  611         m_discoveryRadius = (int)request->getFieldAsUInt32(VID_DISCOVERY_RADIUS);
  612 
  613     if (request->isFieldExist(VID_LINK_COLOR))
  614         m_defaultLinkColor = (int)request->getFieldAsUInt32(VID_LINK_COLOR);
  615 
  616     if (request->isFieldExist(VID_LINK_ROUTING))
  617         m_defaultLinkRouting = (int)request->getFieldAsInt16(VID_LINK_ROUTING);
  618 
  619     if (request->isFieldExist(VID_DISPLAY_MODE))
  620       m_objectDisplayMode = (int)request->getFieldAsInt16(VID_DISPLAY_MODE);
  621 
  622     if (request->isFieldExist(VID_BACKGROUND_COLOR))
  623         m_backgroundColor = (int)request->getFieldAsUInt32(VID_BACKGROUND_COLOR);
  624 
  625     if (request->isFieldExist(VID_BACKGROUND))
  626     {
  627         m_background = request->getFieldAsGUID(VID_BACKGROUND);
  628         m_backgroundLatitude = request->getFieldAsDouble(VID_BACKGROUND_LATITUDE);
  629         m_backgroundLongitude = request->getFieldAsDouble(VID_BACKGROUND_LONGITUDE);
  630         m_backgroundZoom = (int)request->getFieldAsUInt16(VID_BACKGROUND_ZOOM);
  631     }
  632 
  633    if (request->isFieldExist(VID_FILTER))
  634    {
  635       TCHAR *filter = request->getFieldAsString(VID_FILTER);
  636       if (filter != nullptr)
  637          StrStrip(filter);
  638       setFilter(filter);
  639       MemFree(filter);
  640    }
  641 
  642     if (request->isFieldExist(VID_NUM_ELEMENTS))
  643     {
  644         m_elements->clear();
  645 
  646         int numElements = (int)request->getFieldAsUInt32(VID_NUM_ELEMENTS);
  647         if (numElements > 0)
  648         {
  649             UINT32 varId = VID_ELEMENT_LIST_BASE;
  650             for(int i = 0; i < numElements; i++)
  651             {
  652                 NetworkMapElement *e;
  653                 int type = (int)request->getFieldAsUInt16(varId + 1);
  654                 switch(type)
  655                 {
  656                     case MAP_ELEMENT_OBJECT:
  657                         e = new NetworkMapObject(request, varId);
  658                         break;
  659                     case MAP_ELEMENT_DECORATION:
  660                         e = new NetworkMapDecoration(request, varId);
  661                         break;
  662                case MAP_ELEMENT_DCI_CONTAINER:
  663                   e = new NetworkMapDCIContainer(request, varId);
  664                   break;
  665                case MAP_ELEMENT_DCI_IMAGE:
  666                   e = new NetworkMapDCIImage(request, varId);
  667                   break;
  668                case MAP_ELEMENT_TEXT_BOX:
  669                   e = new NetworkMapTextBox(request, varId);
  670                   break;
  671                     default:        // Unknown type, create generic element
  672                         e = new NetworkMapElement(request, varId);
  673                         break;
  674                 }
  675                 m_elements->add(e);
  676                 varId += 100;
  677 
  678                 if (m_nextElementId <= e->getId())
  679                     m_nextElementId = e->getId() + 1;
  680             }
  681         }
  682 
  683         m_links->clear();
  684         int numLinks = request->getFieldAsUInt32(VID_NUM_LINKS);
  685         if (numLinks > 0)
  686         {
  687             UINT32 varId = VID_LINK_LIST_BASE;
  688             for(int i = 0; i < numLinks; i++)
  689             {
  690                 m_links->add(new NetworkMapLink(request, varId));
  691                 varId += 20;
  692             }
  693         }
  694     }
  695 
  696     return super::modifyFromMessageInternal(request);
  697 }
  698 
  699 /**
  700  * Update map content for seeded map types
  701  */
  702 void NetworkMap::updateContent()
  703 {
  704    nxlog_debug_tag(DEBUG_TAG_NETMAP, 6, _T("NetworkMap::updateContent(%s [%u]): map type %d"), m_name, m_id, m_mapType);
  705    if (m_mapType != MAP_TYPE_CUSTOM && m_status != STATUS_UNMANAGED)
  706    {
  707       NetworkMapObjectList objects;
  708       bool topologyRecieved = true;
  709       for(int i = 0; i < m_seedObjects->size(); i++)
  710       {
  711          shared_ptr<Node> seed = static_pointer_cast<Node>(FindObjectById(m_seedObjects->get(i), OBJECT_NODE));
  712          if (seed != nullptr)
  713          {
  714             UINT32 status;
  715             NetworkMapObjectList *topology;
  716             switch(m_mapType)
  717             {
  718                case MAP_TYPE_LAYER2_TOPOLOGY:
  719                   topology = seed->buildL2Topology(&status, m_discoveryRadius, (m_flags & MF_SHOW_END_NODES) != 0);
  720                   break;
  721                case MAP_TYPE_IP_TOPOLOGY:
  722                   topology = seed->buildIPTopology(&status, m_discoveryRadius, (m_flags & MF_SHOW_END_NODES) != 0);
  723                   break;
  724                case MAP_INTERNAL_COMMUNICATION_TOPOLOGY:
  725                   topology = seed->buildInternalCommunicationTopology();
  726                   break;
  727                default:
  728                   topology = nullptr;
  729                   break;
  730             }
  731             if (topology != nullptr)
  732             {
  733                objects.merge(*topology);
  734                delete topology;
  735             }
  736             else
  737             {
  738                nxlog_debug_tag(DEBUG_TAG_NETMAP, 3, _T("NetworkMap::updateContent(%s [%u]): cannot get topology information for node %s [%d], map won't be updated"), m_name, m_id, seed->getName(), seed->getId());
  739                topologyRecieved = false;
  740                break;
  741             }
  742          }
  743          else
  744          {
  745             nxlog_debug_tag(DEBUG_TAG_NETMAP, 3, _T("NetworkMap::updateContent(%s [%u]): seed object %d cannot be found"), m_name, m_id, m_seedObjects->get(i));
  746          }
  747       }
  748       if (!IsShutdownInProgress() && topologyRecieved)
  749       {
  750          updateObjects(&objects);
  751       }
  752    }
  753    nxlog_debug_tag(DEBUG_TAG_NETMAP, 6, _T("NetworkMap::updateContent(%s [%u]): completed"), m_name, m_id);
  754 }
  755 
  756 /**
  757  * Object filter for NetworkMapObjectList::filterObjects
  758  */
  759 bool NetworkMap::objectFilter(uint32_t objectId, NetworkMap *map)
  760 {
  761    shared_ptr<NetObj> object = FindObjectById(objectId);
  762    return (object != nullptr) && map->isAllowedOnMap(object);
  763 }
  764 
  765 /**
  766  * Update objects from given list
  767  */
  768 void NetworkMap::updateObjects(NetworkMapObjectList *objects)
  769 {
  770    bool modified = false;
  771 
  772    nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u]): updateObjects called"), m_name, m_id);
  773 
  774    // Filter out disallowed objects
  775    if ((m_flags & MF_FILTER_OBJECTS) && (m_filter != nullptr))
  776    {
  777       nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u]): running object filter"), m_name, m_id);
  778       objects->filterObjects(NetworkMap::objectFilter, this);
  779    }
  780 
  781    lockProperties();
  782 
  783    // remove non-existing links
  784    for(int i = 0; i < m_links->size(); i++)
  785    {
  786       NetworkMapLink *link = m_links->get(i);
  787       if (!link->checkFlagSet(AUTO_GENERATED))
  788          continue;
  789 
  790       uint32_t objID1 = objectIdFromElementId(link->getElement1());
  791       uint32_t objID2 = objectIdFromElementId(link->getElement2());
  792       bool linkExists = false;
  793       if (objects->isLinkExist(objID1, objID2))
  794       {
  795          linkExists = true;
  796       }
  797       else if (objects->isLinkExist(objID2, objID1))
  798       {
  799          link->swap();
  800          linkExists = true;
  801       }
  802 
  803       if (!linkExists)
  804       {
  805          nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u])/updateObjects: link %u - %u removed"), m_name, m_id, link->getElement1(), link->getElement2());
  806          m_links->remove(i);
  807          i--;
  808          modified = true;
  809       }
  810    }
  811 
  812    // remove non-existing objects
  813    for(int i = 0; i < m_elements->size(); i++)
  814    {
  815       NetworkMapElement *e = m_elements->get(i);
  816       if ((e->getType() != MAP_ELEMENT_OBJECT) || !(e->getFlags() & AUTO_GENERATED))
  817          continue;
  818 
  819       UINT32 objectId = static_cast<NetworkMapObject*>(e)->getObjectId();
  820       if (!objects->isObjectExist(objectId))
  821       {
  822          nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u])/updateObjects: object element %u (object %u) removed"), m_name, m_id, e->getId(), objectId);
  823          m_elements->remove(i);
  824          i--;
  825          modified = true;
  826       }
  827    }
  828 
  829    // add new objects
  830    for(int i = 0; i < objects->getNumObjects(); i++)
  831    {
  832       bool found = false;
  833       for(int j = 0; j < m_elements->size(); j++)
  834       {
  835          NetworkMapElement *e = m_elements->get(j);
  836          if (e->getType() != MAP_ELEMENT_OBJECT)
  837             continue;
  838          if (((NetworkMapObject *)e)->getObjectId() == objects->getObjects().get(i))
  839          {
  840             found = true;
  841             break;
  842          }
  843       }
  844       if (!found)
  845       {
  846          uint32_t objectId = objects->getObjects().get(i);
  847          NetworkMapElement *e = new NetworkMapObject(m_nextElementId++, objectId, 1);
  848          m_elements->add(e);
  849          modified = true;
  850          nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u])/updateObjects: new object %u (element ID %u) added"), m_name, m_id, objectId, e->getId());
  851       }
  852    }
  853 
  854    // add new links
  855    const ObjectArray<ObjLink>& links = objects->getLinks();
  856    for(int i = 0; i < links.size(); i++)
  857    {
  858       ObjLink *newLink = links.get(i);
  859       bool found = false;
  860       for(int j = 0; j < m_links->size(); j++)
  861       {
  862          NetworkMapLink *currLink = m_links->get(j);
  863          uint32_t obj1 = objectIdFromElementId(currLink->getElement1());
  864          uint32_t obj2 = objectIdFromElementId(currLink->getElement2());
  865          if ((newLink->id1 == obj1) && (newLink->id2 == obj2) && (newLink->type == currLink->getType()))
  866          {
  867             found = true;
  868             break;
  869          }
  870       }
  871       if (!found)
  872       {
  873          uint32_t e1 = elementIdFromObjectId(newLink->id1);
  874          uint32_t e2 = elementIdFromObjectId(newLink->id2);
  875          // Element ID can be 0 if link points to object removed by filter
  876          if ((e1 != 0) && (e2 != 0))
  877          {
  878             NetworkMapLink *l = new NetworkMapLink(e1, e2, newLink->type);
  879             l->setConnector1Name(newLink->port1);
  880             l->setConnector2Name(newLink->port2);
  881             l->setName(newLink->name);
  882             StringBuffer config;
  883             config.append(_T("<config>\n"));
  884             config.append(_T("\t<dciList length=\"0\"/>\n"));
  885             config.append(_T("\t<objectStatusList class=\"java.util.ArrayList\">\n"));
  886 
  887             shared_ptr<Node> node = static_pointer_cast<Node>(FindObjectById(newLink->id1, OBJECT_NODE));
  888             if (node != nullptr)
  889             {
  890                for(int n = 0; n < links.get(i)->portIdCount; n++)
  891                {
  892                   shared_ptr<Interface> iface = node->findInterfaceByIndex(newLink->portIdArray1[n]);
  893                   if (iface != nullptr)
  894                   {
  895                      config.append(_T("\t\t<long>"));
  896                      config.append(iface->getId());
  897                      config.append(_T("</long>\n"));
  898                   }
  899                }
  900             }
  901 
  902             node = static_pointer_cast<Node>(FindObjectById(newLink->id2, OBJECT_NODE));
  903             if (node != nullptr)
  904             {
  905                for(int n = 0; n < newLink->portIdCount; n++)
  906                {
  907                   shared_ptr<Interface> iface = node->findInterfaceByIndex(newLink->portIdArray2[n]);
  908                   if (iface != nullptr)
  909                   {
  910                      config.append(_T("\t\t<long>"));
  911                      config.append(iface->getId());
  912                      config.append(_T("</long>\n"));
  913                   }
  914                }
  915             }
  916 
  917             config.append(_T("\t</objectStatusList>\n"));
  918             config.append(_T("\t<color>-1</color>\n"));
  919             config.append(_T("\t<routing>0</routing>\n"));
  920             config.append(_T("</config>"));
  921             l->setConfig(config);
  922             l->setFlags(AUTO_GENERATED);
  923             m_links->add(l);
  924             modified = true;
  925             nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u])/updateObjects: link %u (%u) - %u (%u) added"),
  926                      m_name, m_id, l->getElement1(), newLink->id1, l->getElement2(), newLink->id2);
  927          }
  928          else
  929          {
  930             nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s [%u])/updateObjects: cannot add link because elements are missing for object pair (%u,%u)"),
  931                      m_name, m_id, newLink->id1, newLink->id2);
  932          }
  933       }
  934    }
  935 
  936    if (modified)
  937       setModified(MODIFY_MAP_CONTENT);
  938 
  939    unlockProperties();
  940    nxlog_debug_tag(DEBUG_TAG_NETMAP, 5, _T("NetworkMap(%s): updateObjects completed"), m_name);
  941 }
  942 
  943 /**
  944  * Get object ID from map element ID
  945  * Assumes that object data already locked
  946  */
  947 UINT32 NetworkMap::objectIdFromElementId(UINT32 eid)
  948 {
  949     for(int i = 0; i < m_elements->size(); i++)
  950     {
  951         NetworkMapElement *e = m_elements->get(i);
  952         if (e->getId() == eid)
  953         {
  954             if (e->getType() == MAP_ELEMENT_OBJECT)
  955             {
  956                 return ((NetworkMapObject *)e)->getObjectId();
  957             }
  958             else
  959             {
  960                 return 0;
  961             }
  962         }
  963     }
  964     return 0;
  965 }
  966 
  967 /**
  968  * Get map element ID from object ID
  969  * Assumes that object data already locked
  970  */
  971 UINT32 NetworkMap::elementIdFromObjectId(UINT32 oid)
  972 {
  973     for(int i = 0; i < m_elements->size(); i++)
  974     {
  975         NetworkMapElement *e = m_elements->get(i);
  976         if ((e->getType() == MAP_ELEMENT_OBJECT) && (((NetworkMapObject *)e)->getObjectId() == oid))
  977         {
  978             return e->getId();
  979         }
  980     }
  981     return 0;
  982 }
  983 
  984 /**
  985  * Set filter. Object properties must be already locked.
  986  *
  987  * @param filter new filter script code or nullptr to clear filter
  988  */
  989 void NetworkMap::setFilter(const TCHAR *filter)
  990 {
  991     MemFree(m_filterSource);
  992     delete m_filter;
  993     if ((filter != nullptr) && (*filter != 0))
  994     {
  995         TCHAR error[256];
  996 
  997         m_filterSource = MemCopyString(filter);
  998         m_filter = NXSLCompileAndCreateVM(m_filterSource, error, 256, new NXSL_ServerEnv);
  999         if (m_filter == nullptr)
 1000             nxlog_write(NXLOG_WARNING, _T("Failed to compile filter script for network map object %s [%u] (%s)"), m_name, m_id, error);
 1001     }
 1002     else
 1003     {
 1004         m_filterSource = nullptr;
 1005         m_filter = nullptr;
 1006     }
 1007 }
 1008 
 1009 /**
 1010  * Check if given object should be placed on map
 1011  */
 1012 bool NetworkMap::isAllowedOnMap(const shared_ptr<NetObj>& object)
 1013 {
 1014     bool result = true;
 1015 
 1016     lockProperties();
 1017     if (m_filter != nullptr)
 1018     {
 1019        SetupServerScriptVM(m_filter, object, shared_ptr<DCObjectInfo>());
 1020         if (m_filter->run())
 1021         {
 1022             result = m_filter->getResult()->getValueAsBoolean();
 1023         }
 1024         else
 1025         {
 1026             TCHAR buffer[1024];
 1027             _sntprintf(buffer, 1024, _T("NetworkMap::%s::%d"), m_name, m_id);
 1028             PostSystemEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, m_filter->getErrorText(), m_id);
 1029          nxlog_write(NXLOG_WARNING, _T("Failed to execute filter script for network map object %s [%u] (%s)"), m_name, m_id, m_filter->getErrorText());
 1030         }
 1031     }
 1032     unlockProperties();
 1033     return result;
 1034 }
 1035 
 1036 /**
 1037 *  Delete object from the map if it's deleted in session
 1038 */
 1039 void NetworkMap::onObjectDelete(UINT32 dwObjectId)
 1040 {
 1041    lockProperties();
 1042    uint32_t elementId = elementIdFromObjectId(dwObjectId);
 1043    int i = 0;
 1044    while(i < m_links->size())
 1045    {
 1046       NetworkMapLink* nmLink = (NetworkMapLink*) m_links->get(i);
 1047 
 1048       if (nmLink->getElement1() == elementId || nmLink->getElement2() == elementId)
 1049       {
 1050          m_links->remove(i);
 1051       }
 1052       else
 1053       {
 1054          i++;
 1055       }
 1056    }
 1057 
 1058    i = 0;
 1059    while(i < m_elements->size())
 1060    {
 1061       NetworkMapObject* nmObject = (NetworkMapObject*) m_elements->get(i);
 1062       if (nmObject->getObjectId() == dwObjectId)
 1063       {
 1064          m_elements->remove(i);
 1065          break;
 1066       }
 1067       else
 1068       {
 1069          i++;
 1070       }
 1071    }
 1072 
 1073    setModified(MODIFY_MAP_CONTENT);
 1074 
 1075    unlockProperties();
 1076 
 1077    super::onObjectDelete(dwObjectId);
 1078 }
 1079 
 1080 /**
 1081  * Serialize object to JSON
 1082  */
 1083 json_t *NetworkMap::toJson()
 1084 {
 1085    json_t *root = super::toJson();
 1086 
 1087    lockProperties();
 1088 
 1089    json_object_set_new(root, "mapType", json_integer(m_mapType));
 1090    json_object_set_new(root, "seedObjects", m_seedObjects->toJson());
 1091    json_object_set_new(root, "discoveryRadius", json_integer(m_discoveryRadius));
 1092    json_object_set_new(root, "layout", json_integer(m_layout));
 1093    json_object_set_new(root, "flags", json_integer(m_flags));
 1094    json_object_set_new(root, "backgroundColor", json_integer(m_backgroundColor));
 1095    json_object_set_new(root, "defaultLinkColor", json_integer(m_defaultLinkColor));
 1096    json_object_set_new(root, "defaultLinkRouting", json_integer(m_defaultLinkRouting));
 1097    json_object_set_new(root, "objectDisplayMode", json_integer(m_objectDisplayMode));
 1098    json_object_set_new(root, "background", m_background.toJson());
 1099    json_object_set_new(root, "backgroundLatitude", json_real(m_backgroundLatitude));
 1100    json_object_set_new(root, "backgroundLongitude", json_real(m_backgroundLongitude));
 1101    json_object_set_new(root, "backgroundZoom", json_integer(m_backgroundZoom));
 1102    json_object_set_new(root, "elements", json_object_array(m_elements));
 1103    json_object_set_new(root, "links", json_object_array(m_links));
 1104    json_object_set_new(root, "filter", json_string_t(m_filterSource));
 1105 
 1106    unlockProperties();
 1107    return root;
 1108 }