all pollers converted to single thread pool
[public/netxms.git] / src / server / core / bizservice.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2011 NetXMS Team
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(UINT32 id)
62 {
63 if (!ServiceContainer::loadFromDatabase(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(g_hCoreDB, _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(g_hCoreDB, 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 DbgPrintf(5, _T("Started polling of business service %s [%d]"), m_name, (int)m_id);
210 m_lastPollTime = time(NULL);
211
212 // Loop through the kids and execute their either scripts or thresholds
213 LockChildList(FALSE);
214 for (UINT32 i = 0; i < m_dwChildCount; i++)
215 {
216 if (m_pChildList[i]->getObjectClass() == OBJECT_SLMCHECK)
217 ((SlmCheck *)m_pChildList[i])->execute();
218 else if (m_pChildList[i]->getObjectClass() == OBJECT_NODELINK)
219 ((NodeLink*)m_pChildList[i])->execute();
220 }
221 UnlockChildList();
222
223 // Set the status based on what the kids' been up to
224 calculateCompoundStatus();
225
226 m_lastPollStatus = m_iStatus;
227 DbgPrintf(5, _T("Finished polling of business service %s [%d]"), m_name, (int)m_id);
228 m_busy = false;
229 }
230
231 /**
232 * Get template checks applicable for given target
233 */
234 void BusinessService::getApplicableTemplates(ServiceContainer *target, ObjectArray<SlmCheck> *templates)
235 {
236 LockChildList(FALSE);
237 for(UINT32 i = 0; i < m_dwChildCount; i++)
238 {
239 if ((m_pChildList[i]->getObjectClass() == OBJECT_SLMCHECK) &&
240 ((SlmCheck *)m_pChildList[i])->isTemplate())
241 {
242 m_pChildList[i]->incRefCount();
243 templates->add((SlmCheck *)m_pChildList[i]);
244 }
245 }
246 UnlockChildList();
247
248 LockParentList(FALSE);
249 for(UINT32 i = 0; i < m_dwParentCount; i++)
250 {
251 if (m_pParentList[i]->getObjectClass() == OBJECT_BUSINESSSERVICE)
252 {
253 ((BusinessService *)m_pParentList[i])->getApplicableTemplates(target, templates);
254 }
255 }
256 UnlockParentList();
257 }
258
259 /**
260 * Prepare business service object for deletion
261 */
262 void BusinessService::prepareForDeletion()
263 {
264 // Prevent service from being queued for polling
265 lockProperties();
266 m_pollingDisabled = true;
267 unlockProperties();
268
269 // wait for outstanding poll to complete
270 while(true)
271 {
272 lockProperties();
273 if (!m_busy)
274 {
275 unlockProperties();
276 break;
277 }
278 unlockProperties();
279 ThreadSleep(100);
280 }
281 DbgPrintf(4, _T("BusinessService::PrepareForDeletion(%s [%d]): no outstanding polls left"), m_name, (int)m_id);
282 ServiceContainer::prepareForDeletion();
283 }