object save optimization - object properties divided into groups and anly modified...
[public/netxms.git] / src / server / core / mobile.cpp
CommitLineData
4899db4d 1/*
f22c4f7c 2** NetXMS - Network Management System
db091a1f 3** Copyright (C) 2003-2016 Victor Kirhenshtein
f22c4f7c
VK
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: mobile.cpp
f22c4f7c
VK
20**/
21
22#include "nxcore.h"
23
24/**
25 * Default constructor
26 */
6fd6de0a 27MobileDevice::MobileDevice() : DataCollectionTarget()
f22c4f7c
VK
28{
29 m_lastReportTime = 0;
30 m_deviceId = NULL;
31 m_vendor = NULL;
32 m_model = NULL;
33 m_serialNumber = NULL;
34 m_osName = NULL;
35 m_osVersion = NULL;
36 m_userId = NULL;
171c2fd6 37 m_batteryLevel = -1;
f22c4f7c
VK
38}
39
40/**
41 * Constructor for creating new mobile device object
42 */
6fd6de0a 43MobileDevice::MobileDevice(const TCHAR *name, const TCHAR *deviceId) : DataCollectionTarget(name)
f22c4f7c
VK
44{
45 m_lastReportTime = 0;
46 m_deviceId = _tcsdup(deviceId);
47 m_vendor = NULL;
48 m_model = NULL;
49 m_serialNumber = NULL;
50 m_osName = NULL;
51 m_osVersion = NULL;
52 m_userId = NULL;
171c2fd6 53 m_batteryLevel = -1;
f22c4f7c
VK
54}
55
56/**
57 * Destructor
58 */
59MobileDevice::~MobileDevice()
60{
61 safe_free(m_deviceId);
62 safe_free(m_vendor);
63 safe_free(m_model);
64 safe_free(m_serialNumber);
65 safe_free(m_osName);
66 safe_free(m_osVersion);
67 safe_free(m_userId);
68}
9aa67910
VK
69
70/**
71 * Create object from database data
72 */
9bd1bace 73bool MobileDevice::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
9aa67910 74{
c42b4551 75 m_id = dwId;
9aa67910 76
9bd1bace 77 if (!loadCommonProperties(hdb))
9aa67910 78 {
4dd963e9 79 DbgPrintf(2, _T("Cannot load common properties for mobile device object %d"), dwId);
9bd1bace 80 return false;
9aa67910
VK
81 }
82
83 TCHAR query[256];
c42b4551 84 _sntprintf(query, 256, _T("SELECT device_id,vendor,model,serial_number,os_name,os_version,user_id,battery_level FROM mobile_devices WHERE id=%d"), (int)m_id);
9bd1bace 85 DB_RESULT hResult = DBSelect(hdb, query);
9aa67910 86 if (hResult == NULL)
9bd1bace 87 return false;
9aa67910
VK
88
89 m_deviceId = DBGetField(hResult, 0, 0, NULL, 0);
90 m_vendor = DBGetField(hResult, 0, 1, NULL, 0);
91 m_model = DBGetField(hResult, 0, 2, NULL, 0);
92 m_serialNumber = DBGetField(hResult, 0, 3, NULL, 0);
93 m_osName = DBGetField(hResult, 0, 4, NULL, 0);
94 m_osVersion = DBGetField(hResult, 0, 5, NULL, 0);
95 m_userId = DBGetField(hResult, 0, 6, NULL, 0);
171c2fd6 96 m_batteryLevel = DBGetFieldLong(hResult, 0, 7);
9aa67910
VK
97 DBFreeResult(hResult);
98
99 // Load DCI and access list
9bd1bace
VK
100 loadACLFromDB(hdb);
101 loadItemsFromDB(hdb);
9aa67910 102 for(int i = 0; i < m_dcObjects->size(); i++)
9bd1bace
VK
103 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
104 return false;
9aa67910 105
9bd1bace 106 return true;
9aa67910
VK
107}
108
109/**
110 * Save object to database
111 */
b4277312 112bool MobileDevice::saveToDatabase(DB_HANDLE hdb)
9aa67910
VK
113{
114 // Lock object's access
c42b4551 115 lockProperties();
9aa67910 116
3d48d1b4 117 bool success = saveCommonProperties(hdb);
9aa67910 118
3d48d1b4
VK
119 if (success && (m_modified & MODIFY_OTHER))
120 {
121 DB_STATEMENT hStmt;
122 if (IsDatabaseRecordExist(hdb, _T("mobile_devices"), _T("id"), m_id))
123 hStmt = DBPrepare(hdb, _T("UPDATE mobile_devices SET device_id=?,vendor=?,model=?,serial_number=?,os_name=?,os_version=?,user_id=?,battery_level=? WHERE id=?"));
124 else
125 hStmt = DBPrepare(hdb, _T("INSERT INTO mobile_devices (device_id,vendor,model,serial_number,os_name,os_version,user_id,battery_level,id) VALUES (?,?,?,?,?,?,?,?,?)"));
126 if (hStmt != NULL)
127 {
128 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_deviceId), DB_BIND_STATIC);
129 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_vendor), DB_BIND_STATIC);
130 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_model), DB_BIND_STATIC);
131 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_serialNumber), DB_BIND_STATIC);
132 DBBind(hStmt, 5, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_osName), DB_BIND_STATIC);
133 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_osVersion), DB_BIND_STATIC);
134 DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, CHECK_NULL_EX(m_userId), DB_BIND_STATIC);
135 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, m_batteryLevel);
136 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, m_id);
137
138 success = DBExecute(hStmt);
139
140 DBFreeStatement(hStmt);
141 }
142 else
143 {
144 success = false;
145 }
146 }
9aa67910
VK
147
148 // Save data collection items
3d48d1b4 149 if (success && (m_modified & MODIFY_DATA_COLLECTION))
9aa67910 150 {
b06436f4 151 lockDciAccess(false);
9aa67910 152 for(int i = 0; i < m_dcObjects->size(); i++)
e7450f3b 153 m_dcObjects->get(i)->saveToDatabase(hdb);
9aa67910
VK
154 unlockDciAccess();
155 }
156
157 // Save access list
3d48d1b4
VK
158 if (success)
159 success = saveACLToDB(hdb);
9aa67910
VK
160
161 // Clear modifications flag and unlock object
3d48d1b4
VK
162 if (success)
163 m_modified = 0;
c42b4551 164 unlockProperties();
9aa67910 165
3d48d1b4 166 return success;
9aa67910
VK
167}
168
169/**
170 * Delete object from database
171 */
c42b4551 172bool MobileDevice::deleteFromDatabase(DB_HANDLE hdb)
9aa67910 173{
c42b4551 174 bool success = DataCollectionTarget::deleteFromDatabase(hdb);
22ee6d97
VK
175 if (success)
176 success = executeQueryOnObject(hdb, _T("DELETE FROM mobile_devices WHERE id=?"));
177 return success;
9aa67910
VK
178}
179
180/**
181 * Create CSCP message with object's data
182 */
8fe90adb 183void MobileDevice::fillMessageInternal(NXCPMessage *msg)
9aa67910 184{
8fe90adb 185 DataCollectionTarget::fillMessageInternal(msg);
e83d726c 186
b368969c
VK
187 msg->setField(VID_DEVICE_ID, CHECK_NULL_EX(m_deviceId));
188 msg->setField(VID_VENDOR, CHECK_NULL_EX(m_vendor));
189 msg->setField(VID_MODEL, CHECK_NULL_EX(m_model));
190 msg->setField(VID_SERIAL_NUMBER, CHECK_NULL_EX(m_serialNumber));
191 msg->setField(VID_OS_NAME, CHECK_NULL_EX(m_osName));
192 msg->setField(VID_OS_VERSION, CHECK_NULL_EX(m_osVersion));
193 msg->setField(VID_USER_ID, CHECK_NULL_EX(m_userId));
194 msg->setField(VID_BATTERY_LEVEL, (UINT32)m_batteryLevel);
195 msg->setField(VID_LAST_CHANGE_TIME, (QWORD)m_lastReportTime);
9aa67910
VK
196}
197
198/**
199 * Modify object from message
200 */
8fe90adb 201UINT32 MobileDevice::modifyFromMessageInternal(NXCPMessage *pRequest)
9aa67910 202{
8fe90adb 203 return DataCollectionTarget::modifyFromMessageInternal(pRequest);
9aa67910 204}
6583a0f8
VK
205
206/**
207 * Update system information from NXCP message
208 */
b368969c 209void MobileDevice::updateSystemInfo(NXCPMessage *msg)
6583a0f8 210{
c42b4551 211 lockProperties();
6583a0f8 212
63862632
VK
213 m_lastReportTime = time(NULL);
214
3d48d1b4 215 free(m_vendor);
b368969c 216 m_vendor = msg->getFieldAsString(VID_VENDOR);
6583a0f8 217
3d48d1b4 218 free(m_model);
b368969c 219 m_model = msg->getFieldAsString(VID_MODEL);
6583a0f8 220
3d48d1b4 221 free(m_serialNumber);
b368969c 222 m_serialNumber = msg->getFieldAsString(VID_SERIAL_NUMBER);
6583a0f8 223
3d48d1b4 224 free(m_osName);
b368969c 225 m_osName = msg->getFieldAsString(VID_OS_NAME);
6583a0f8 226
3d48d1b4 227 free(m_osVersion);
b368969c 228 m_osVersion = msg->getFieldAsString(VID_OS_VERSION);
6583a0f8 229
3d48d1b4 230 free(m_userId);
b368969c 231 m_userId = msg->getFieldAsString(VID_USER_NAME);
6583a0f8 232
3d48d1b4 233 setModified(MODIFY_OTHER);
c42b4551 234 unlockProperties();
6583a0f8
VK
235}
236
237/**
238 * Update status from NXCP message
239 */
b368969c 240void MobileDevice::updateStatus(NXCPMessage *msg)
6583a0f8 241{
c42b4551 242 lockProperties();
6583a0f8 243
63862632
VK
244 m_lastReportTime = time(NULL);
245
4101571e 246 int type = msg->getFieldType(VID_BATTERY_LEVEL);
b368969c
VK
247 if (type == NXCP_DT_INT32)
248 m_batteryLevel = msg->getFieldAsInt32(VID_BATTERY_LEVEL);
249 else if (type == NXCP_DT_INT16)
250 m_batteryLevel = (int)msg->getFieldAsInt16(VID_BATTERY_LEVEL);
6583a0f8
VK
251 else
252 m_batteryLevel = -1;
253
5c44534b 254 if (msg->isFieldExist(VID_GEOLOCATION_TYPE))
4899db4d 255 {
6583a0f8 256 m_geoLocation = GeoLocation(*msg);
4899db4d 257 addLocationToHistory();
258 }
6583a0f8 259
5c44534b 260 if (msg->isFieldExist(VID_IP_ADDRESS))
c75e9ee4 261 m_ipAddress = msg->getFieldAsInetAddress(VID_IP_ADDRESS);
6583a0f8 262
c75e9ee4 263 TCHAR temp[64];
6583a0f8 264 DbgPrintf(5, _T("Mobile device %s [%d] updated from agent (battery=%d addr=%s loc=[%s %s])"),
c75e9ee4 265 m_name, (int)m_id, m_batteryLevel, m_ipAddress.toString(temp),
6583a0f8
VK
266 m_geoLocation.getLatitudeAsString(), m_geoLocation.getLongitudeAsString());
267
3d48d1b4 268 setModified(MODIFY_OTHER);
c42b4551 269 unlockProperties();
6583a0f8 270}
eb0c0312
VK
271
272/**
273 * Get value for server's internal parameter
274 */
17b1ab4a 275UINT32 MobileDevice::getInternalItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
eb0c0312 276{
967893bb 277 UINT32 rc = DataCollectionTarget::getInternalItem(param, bufSize, buffer);
192cb389
VK
278 if (rc != DCE_NOT_SUPPORTED)
279 return rc;
eb0c0312
VK
280 rc = DCE_SUCCESS;
281
282 if (!_tcsicmp(param, _T("MobileDevice.BatteryLevel")))
283 {
284 _sntprintf(buffer, bufSize, _T("%d"), m_batteryLevel);
285 }
286 else if (!_tcsicmp(param, _T("MobileDevice.DeviceId")))
287 {
288 nx_strncpy(buffer, CHECK_NULL_EX(m_deviceId), bufSize);
289 }
290 else if (!_tcsicmp(param, _T("MobileDevice.LastReportTime")))
291 {
292 _sntprintf(buffer, bufSize, INT64_FMT, (INT64)m_lastReportTime);
293 }
294 else if (!_tcsicmp(param, _T("MobileDevice.Model")))
295 {
296 nx_strncpy(buffer, CHECK_NULL_EX(m_model), bufSize);
297 }
298 else if (!_tcsicmp(param, _T("MobileDevice.OS.Name")))
299 {
300 nx_strncpy(buffer, CHECK_NULL_EX(m_osName), bufSize);
301 }
302 else if (!_tcsicmp(param, _T("MobileDevice.OS.Version")))
303 {
304 nx_strncpy(buffer, CHECK_NULL_EX(m_osVersion), bufSize);
305 }
306 else if (!_tcsicmp(param, _T("MobileDevice.SerialNumber")))
307 {
308 nx_strncpy(buffer, CHECK_NULL_EX(m_serialNumber), bufSize);
309 }
310 else if (!_tcsicmp(param, _T("MobileDevice.Vendor")))
311 {
312 nx_strncpy(buffer, CHECK_NULL_EX(m_vendor), bufSize);
313 }
314 else if (!_tcsicmp(param, _T("MobileDevice.UserId")))
315 {
316 nx_strncpy(buffer, CHECK_NULL_EX(m_userId), bufSize);
317 }
318 else
319 {
320 rc = DCE_NOT_SUPPORTED;
321 }
322
323 return rc;
324}
26e2b253
VK
325
326/**
327 * Calculate compound status
328 */
329void MobileDevice::calculateCompoundStatus(BOOL bForcedRecalc)
330{
331 NetObj::calculateCompoundStatus(bForcedRecalc);
332
333 // Assume normal status by default for mobile device
db091a1f 334 if (m_status == STATUS_UNKNOWN)
26e2b253 335 {
c42b4551 336 lockProperties();
db091a1f 337 m_status = STATUS_NORMAL;
3d48d1b4 338 setModified(MODIFY_RUNTIME);
c42b4551 339 unlockProperties();
26e2b253
VK
340 }
341}
297a88eb
VK
342
343/**
344 * Create NXSL object for this object
345 */
346NXSL_Value *MobileDevice::createNXSLObject()
347{
348 return new NXSL_Value(new NXSL_Object(&g_nxslMobileDeviceClass, this));
349}
950b229b
VK
350
351/**
352 * Serialize object to JSON
353 */
354json_t *MobileDevice::toJson()
355{
356 json_t *root = DataCollectionTarget::toJson();
357 json_object_set_new(root, "lastReportTime", json_integer(m_lastReportTime));
358 json_object_set_new(root, "deviceId", json_string_t(m_deviceId));
359 json_object_set_new(root, "vendor", json_string_t(m_vendor));
360 json_object_set_new(root, "model", json_string_t(m_model));
361 json_object_set_new(root, "serialNumber", json_string_t(m_serialNumber));
362 json_object_set_new(root, "osName", json_string_t(m_osName));
363 json_object_set_new(root, "osVersion", json_string_t(m_osVersion));
364 json_object_set_new(root, "userId", json_string_t(m_userId));
365 json_object_set_new(root, "batteryLevel", json_integer(m_batteryLevel));
366 json_object_set_new(root, "ipAddress", m_ipAddress.toJson());
367 return root;
368}