f5bcca2c67aa1d2a7d101d3fc04759750ab79dbe
[public/netxms.git] / src / server / core / bizservice.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 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: bizservice.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 #define QUERY_LENGTH (512)
26
27 /**
28 * Service default constructor
29 */
30 BusinessService::BusinessService() : ServiceContainer()
31 {
32 m_busy = false;
33 m_pollingDisabled = false;
34 m_lastPollTime = time_t(0);
35 m_lastPollStatus = STATUS_UNKNOWN;
36 _tcscpy(m_name, _T("Default"));
37 }
38
39 /**
40 * Constructor for new service object
41 */
42 BusinessService::BusinessService(const TCHAR *name) : ServiceContainer(name)
43 {
44 m_busy = false;
45 m_pollingDisabled = false;
46 m_lastPollTime = time_t(0);
47 m_lastPollStatus = STATUS_UNKNOWN;
48 nx_strncpy(m_name, name, MAX_OBJECT_NAME);
49 }
50
51 /**
52 * Destructor
53 */
54 BusinessService::~BusinessService()
55 {
56 }
57
58 /**
59 * Create object from database data
60 */
61 bool BusinessService::loadFromDatabase(DB_HANDLE hdb, UINT32 id)
62 {
63 if (!ServiceContainer::loadFromDatabase(hdb, id))
64 return FALSE;
65
66 // now it doesn't make any sense but hopefully will do in the future
67 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT service_id FROM business_services WHERE service_id=?"));
68 if (hStmt == NULL)
69 {
70 DbgPrintf(4, _T("Cannot prepare select from business_services"));
71 return FALSE;
72 }
73 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
74 DB_RESULT hResult = DBSelectPrepared(hStmt);
75 if (hResult == NULL)
76 {
77 DBFreeStatement(hStmt);
78 return FALSE;
79 }
80
81 if (DBGetNumRows(hResult) == 0)
82 {
83 DBFreeResult(hResult);
84 DBFreeStatement(hStmt);
85 DbgPrintf(4, _T("Cannot load biz service object %ld - record missing"), (long)m_id);
86 return FALSE;
87 }
88
89 DBFreeResult(hResult);
90 DBFreeStatement(hStmt);
91
92 return TRUE;
93 }
94
95 /**
96 * Save service to database
97 */
98 bool BusinessService::saveToDatabase(DB_HANDLE hdb)
99 {
100 BOOL bNewObject = TRUE;
101
102 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT service_id FROM business_services WHERE service_id=?"));
103 if (hStmt == NULL)
104 return false;
105
106 lockProperties();
107
108 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
109 DB_RESULT hResult = DBSelectPrepared(hStmt);
110 if (hResult != NULL)
111 {
112 bNewObject = (DBGetNumRows(hResult) <= 0);
113 DBFreeResult(hResult);
114 }
115 DBFreeStatement(hStmt);
116
117 hStmt = DBPrepare(hdb, bNewObject ? _T("INSERT INTO business_services (service_id) VALUES (?)") :
118 _T("UPDATE business_services SET service_id=service_id WHERE service_id=?"));
119 if (hStmt == NULL)
120 {
121 unlockProperties();
122 return false;
123 }
124 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
125 unlockProperties();
126
127 if (!DBExecute(hStmt))
128 {
129 DBFreeStatement(hStmt);
130 return false;
131 }
132
133 DBFreeStatement(hStmt);
134
135 saveACLToDB(hdb);
136
137 lockProperties();
138 m_isModified = false;
139 unlockProperties();
140
141 return ServiceContainer::saveToDatabase(hdb);
142 }
143
144 /**
145 * Delete object from database
146 */
147 bool BusinessService::deleteFromDatabase(DB_HANDLE hdb)
148 {
149 bool success = ServiceContainer::deleteFromDatabase(hdb);
150 if (success)
151 {
152 success = executeQueryOnObject(hdb, _T("DELETE FROM business_services WHERE service_id=?"));
153 }
154 return success;
155 }
156
157 /**
158 * Create NXCP message with object's data
159 */
160 void BusinessService::fillMessageInternal(NXCPMessage *pMsg)
161 {
162 ServiceContainer::fillMessageInternal(pMsg);
163 }
164
165 /**
166 * Modify object from message
167 */
168 UINT32 BusinessService::modifyFromMessageInternal(NXCPMessage *pRequest)
169 {
170 return ServiceContainer::modifyFromMessageInternal(pRequest);
171 }
172
173 /**
174 * Check if service is ready for poll
175 */
176 bool BusinessService::isReadyForPolling()
177 {
178 lockProperties();
179 bool ready = (time(NULL) - m_lastPollTime > g_slmPollingInterval) && !m_busy && !m_pollingDisabled;
180 unlockProperties();
181 return ready;
182 }
183
184 /**
185 * Lock service for polling
186 */
187 void BusinessService::lockForPolling()
188 {
189 lockProperties();
190 m_busy = true;
191 unlockProperties();
192 }
193
194 /**
195 * A callback for poller threads
196 */
197 void BusinessService::poll(PollerInfo *poller)
198 {
199 poller->startExecution();
200 poll(NULL, 0, poller);
201 delete poller;
202 }
203
204 /**
205 * Status poll
206 */
207 void BusinessService::poll(ClientSession *pSession, UINT32 dwRqId, PollerInfo *poller)
208 {
209 if (IsShutdownInProgress())
210 {
211 m_busy = false;
212 return;
213 }
214
215 DbgPrintf(5, _T("Started polling of business service %s [%d]"), m_name, (int)m_id);
216 m_lastPollTime = time(NULL);
217
218 // Loop through the kids and execute their either scripts or thresholds
219 lockChildList(false);
220 for (int i = 0; i < m_childList->size(); i++)
221 {
222 NetObj *object = m_childList->get(i);
223 if (object->getObjectClass() == OBJECT_SLMCHECK)
224 ((SlmCheck *)object)->execute();
225 else if (object->getObjectClass() == OBJECT_NODELINK)
226 ((NodeLink*)object)->execute();
227 }
228 unlockChildList();
229
230 // Set the status based on what the kids' been up to
231 calculateCompoundStatus();
232
233 m_lastPollStatus = m_status;
234 DbgPrintf(5, _T("Finished polling of business service %s [%d]"), m_name, (int)m_id);
235 m_busy = false;
236 }
237
238 /**
239 * Get template checks applicable for given target
240 */
241 void BusinessService::getApplicableTemplates(ServiceContainer *target, ObjectArray<SlmCheck> *templates)
242 {
243 lockChildList(false);
244 for(int i = 0; i < m_childList->size(); i++)
245 {
246 NetObj *object = m_childList->get(i);
247 if ((object->getObjectClass() == OBJECT_SLMCHECK) &&
248 ((SlmCheck *)object)->isTemplate())
249 {
250 object->incRefCount();
251 templates->add((SlmCheck *)object);
252 }
253 }
254 unlockChildList();
255
256 lockParentList(false);
257 for(int i = 0; i < m_parentList->size(); i++)
258 {
259 NetObj *object = m_parentList->get(i);
260 if (object->getObjectClass() == OBJECT_BUSINESSSERVICE)
261 {
262 ((BusinessService *)object)->getApplicableTemplates(target, templates);
263 }
264 }
265 unlockParentList();
266 }
267
268 /**
269 * Prepare business service object for deletion
270 */
271 void BusinessService::prepareForDeletion()
272 {
273 // Prevent service from being queued for polling
274 lockProperties();
275 m_pollingDisabled = true;
276 unlockProperties();
277
278 // wait for outstanding poll to complete
279 while(true)
280 {
281 lockProperties();
282 if (!m_busy)
283 {
284 unlockProperties();
285 break;
286 }
287 unlockProperties();
288 ThreadSleep(100);
289 }
290 DbgPrintf(4, _T("BusinessService::PrepareForDeletion(%s [%d]): no outstanding polls left"), m_name, (int)m_id);
291 ServiceContainer::prepareForDeletion();
292 }