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