object save optimization - object properties divided into groups and anly modified...
[public/netxms.git] / src / server / core / mobile.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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
20 **/
21
22 #include "nxcore.h"
23
24 /**
25 * Default constructor
26 */
27 MobileDevice::MobileDevice() : DataCollectionTarget()
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;
37 m_batteryLevel = -1;
38 }
39
40 /**
41 * Constructor for creating new mobile device object
42 */
43 MobileDevice::MobileDevice(const TCHAR *name, const TCHAR *deviceId) : DataCollectionTarget(name)
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;
53 m_batteryLevel = -1;
54 }
55
56 /**
57 * Destructor
58 */
59 MobileDevice::~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 }
69
70 /**
71 * Create object from database data
72 */
73 bool MobileDevice::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
74 {
75 m_id = dwId;
76
77 if (!loadCommonProperties(hdb))
78 {
79 DbgPrintf(2, _T("Cannot load common properties for mobile device object %d"), dwId);
80 return false;
81 }
82
83 TCHAR query[256];
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);
85 DB_RESULT hResult = DBSelect(hdb, query);
86 if (hResult == NULL)
87 return false;
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);
96 m_batteryLevel = DBGetFieldLong(hResult, 0, 7);
97 DBFreeResult(hResult);
98
99 // Load DCI and access list
100 loadACLFromDB(hdb);
101 loadItemsFromDB(hdb);
102 for(int i = 0; i < m_dcObjects->size(); i++)
103 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
104 return false;
105
106 return true;
107 }
108
109 /**
110 * Save object to database
111 */
112 bool MobileDevice::saveToDatabase(DB_HANDLE hdb)
113 {
114 // Lock object's access
115 lockProperties();
116
117 bool success = saveCommonProperties(hdb);
118
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 }
147
148 // Save data collection items
149 if (success && (m_modified & MODIFY_DATA_COLLECTION))
150 {
151 lockDciAccess(false);
152 for(int i = 0; i < m_dcObjects->size(); i++)
153 m_dcObjects->get(i)->saveToDatabase(hdb);
154 unlockDciAccess();
155 }
156
157 // Save access list
158 if (success)
159 success = saveACLToDB(hdb);
160
161 // Clear modifications flag and unlock object
162 if (success)
163 m_modified = 0;
164 unlockProperties();
165
166 return success;
167 }
168
169 /**
170 * Delete object from database
171 */
172 bool MobileDevice::deleteFromDatabase(DB_HANDLE hdb)
173 {
174 bool success = DataCollectionTarget::deleteFromDatabase(hdb);
175 if (success)
176 success = executeQueryOnObject(hdb, _T("DELETE FROM mobile_devices WHERE id=?"));
177 return success;
178 }
179
180 /**
181 * Create CSCP message with object's data
182 */
183 void MobileDevice::fillMessageInternal(NXCPMessage *msg)
184 {
185 DataCollectionTarget::fillMessageInternal(msg);
186
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);
196 }
197
198 /**
199 * Modify object from message
200 */
201 UINT32 MobileDevice::modifyFromMessageInternal(NXCPMessage *pRequest)
202 {
203 return DataCollectionTarget::modifyFromMessageInternal(pRequest);
204 }
205
206 /**
207 * Update system information from NXCP message
208 */
209 void MobileDevice::updateSystemInfo(NXCPMessage *msg)
210 {
211 lockProperties();
212
213 m_lastReportTime = time(NULL);
214
215 free(m_vendor);
216 m_vendor = msg->getFieldAsString(VID_VENDOR);
217
218 free(m_model);
219 m_model = msg->getFieldAsString(VID_MODEL);
220
221 free(m_serialNumber);
222 m_serialNumber = msg->getFieldAsString(VID_SERIAL_NUMBER);
223
224 free(m_osName);
225 m_osName = msg->getFieldAsString(VID_OS_NAME);
226
227 free(m_osVersion);
228 m_osVersion = msg->getFieldAsString(VID_OS_VERSION);
229
230 free(m_userId);
231 m_userId = msg->getFieldAsString(VID_USER_NAME);
232
233 setModified(MODIFY_OTHER);
234 unlockProperties();
235 }
236
237 /**
238 * Update status from NXCP message
239 */
240 void MobileDevice::updateStatus(NXCPMessage *msg)
241 {
242 lockProperties();
243
244 m_lastReportTime = time(NULL);
245
246 int type = msg->getFieldType(VID_BATTERY_LEVEL);
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);
251 else
252 m_batteryLevel = -1;
253
254 if (msg->isFieldExist(VID_GEOLOCATION_TYPE))
255 {
256 m_geoLocation = GeoLocation(*msg);
257 addLocationToHistory();
258 }
259
260 if (msg->isFieldExist(VID_IP_ADDRESS))
261 m_ipAddress = msg->getFieldAsInetAddress(VID_IP_ADDRESS);
262
263 TCHAR temp[64];
264 DbgPrintf(5, _T("Mobile device %s [%d] updated from agent (battery=%d addr=%s loc=[%s %s])"),
265 m_name, (int)m_id, m_batteryLevel, m_ipAddress.toString(temp),
266 m_geoLocation.getLatitudeAsString(), m_geoLocation.getLongitudeAsString());
267
268 setModified(MODIFY_OTHER);
269 unlockProperties();
270 }
271
272 /**
273 * Get value for server's internal parameter
274 */
275 UINT32 MobileDevice::getInternalItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
276 {
277 UINT32 rc = DataCollectionTarget::getInternalItem(param, bufSize, buffer);
278 if (rc != DCE_NOT_SUPPORTED)
279 return rc;
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 }
325
326 /**
327 * Calculate compound status
328 */
329 void MobileDevice::calculateCompoundStatus(BOOL bForcedRecalc)
330 {
331 NetObj::calculateCompoundStatus(bForcedRecalc);
332
333 // Assume normal status by default for mobile device
334 if (m_status == STATUS_UNKNOWN)
335 {
336 lockProperties();
337 m_status = STATUS_NORMAL;
338 setModified(MODIFY_RUNTIME);
339 unlockProperties();
340 }
341 }
342
343 /**
344 * Create NXSL object for this object
345 */
346 NXSL_Value *MobileDevice::createNXSLObject()
347 {
348 return new NXSL_Value(new NXSL_Object(&g_nxslMobileDeviceClass, this));
349 }
350
351 /**
352 * Serialize object to JSON
353 */
354 json_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 }