vlan view almost working
[public/netxms.git] / src / server / core / job.cpp
CommitLineData
ab621f39
VK
1/*
2** NetXMS - Network Management System
0edd0ab0 3** Copyright (C) 2003-2010 Victor Kirhenshtein
ab621f39
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: job.cpp
20**
21**/
22
23#include "nxcore.h"
24
25
26//
27// Static members
28//
29
30DWORD ServerJob::s_freeId = 1;
31
32
33//
34// Constructor
35//
36
0edd0ab0 37ServerJob::ServerJob(const TCHAR *type, const TCHAR *description, DWORD node, DWORD userId)
ab621f39
VK
38{
39 m_id = s_freeId++;
0edd0ab0 40 m_userId = userId;
ab621f39
VK
41 m_type = _tcsdup(CHECK_NULL(type));
42 m_description = _tcsdup(CHECK_NULL(description));
43 m_status = JOB_PENDING;
3929b1ca
VK
44 m_lastStatusChange = time(NULL);
45 m_autoCancelDelay = 0;
ab621f39 46 m_remoteNode = node;
8134d3a3 47 m_resolvedObject = FindObjectById(m_remoteNode);
ab621f39
VK
48 m_progress = 0;
49 m_failureMessage = NULL;
50 m_owningQueue = NULL;
51 m_workerThread = INVALID_THREAD_HANDLE;
3929b1ca
VK
52 m_lastNotification = 0;
53 m_notificationLock = MutexCreate();
8134d3a3 54 m_blockNextJobsOnFailure = false;
ab621f39
VK
55}
56
57
58//
59// Destructor
60//
61
62ServerJob::~ServerJob()
63{
64 ThreadJoin(m_workerThread);
65
66 safe_free(m_type);
67 safe_free(m_description);
3929b1ca
VK
68 MutexDestroy(m_notificationLock);
69}
70
71
72//
73// Send notification to clients
74//
75
76void ServerJob::sendNotification(ClientSession *session, void *arg)
77{
78 ServerJob *job = (ServerJob *)arg;
e05b1945
VK
79 if (job->m_resolvedObject->CheckAccessRights(session->getUserId(), OBJECT_ACCESS_READ))
80 session->sendMessage(&job->m_notificationMessage);
3929b1ca
VK
81}
82
83
84//
85// Notify clients
86//
87
88void ServerJob::notifyClients(bool isStatusChange)
89{
8134d3a3
VK
90 if (m_resolvedObject == NULL)
91 return;
92
3929b1ca 93 time_t t = time(NULL);
901a5a9b
VK
94 if (!isStatusChange && (t - m_lastNotification < 3))
95 return; // Don't send progress notifications often then every 3 seconds
96 m_lastNotification = t;
3929b1ca
VK
97
98 MutexLock(m_notificationLock, INFINITE);
99 m_notificationMessage.SetCode(CMD_JOB_CHANGE_NOTIFICATION);
100 fillMessage(&m_notificationMessage);
8134d3a3 101 EnumerateClientSessions(ServerJob::sendNotification, this);
3929b1ca
VK
102 MutexUnlock(m_notificationLock);
103}
104
105
106//
107// Change status
108//
109
110void ServerJob::changeStatus(ServerJobStatus newStatus)
111{
112 m_status = newStatus;
113 m_lastStatusChange = time(NULL);
114 notifyClients(true);
ab621f39
VK
115}
116
117
118//
119// Set owning queue
120//
121
122void ServerJob::setOwningQueue(ServerJobQueue *queue)
123{
124 m_owningQueue = queue;
3929b1ca 125 notifyClients(true);
ab621f39
VK
126}
127
128
129//
130// Update progress
131//
132
133void ServerJob::markProgress(int pctCompleted)
134{
135 if ((pctCompleted > m_progress) && (pctCompleted <= 100))
3929b1ca 136 {
ab621f39 137 m_progress = pctCompleted;
3929b1ca
VK
138 notifyClients(false);
139 }
ab621f39
VK
140}
141
142
143//
144// Worker thread starter
145//
146
147THREAD_RESULT THREAD_CALL ServerJob::WorkerThreadStarter(void *arg)
148{
129a1ce0
VK
149 ServerJob *job = (ServerJob *)arg;
150 DbgPrintf(4, _T("Job %d started"), job->m_id);
ab621f39 151
129a1ce0
VK
152 if (job->run())
153 {
3929b1ca 154 job->changeStatus(JOB_COMPLETED);
129a1ce0 155 }
ab621f39 156 else
129a1ce0 157 {
901a5a9b
VK
158 if (job->m_status != JOB_CANCEL_PENDING)
159 job->changeStatus(JOB_FAILED);
129a1ce0
VK
160 }
161 job->m_workerThread = INVALID_THREAD_HANDLE;
ab621f39 162
901a5a9b 163 DbgPrintf(4, _T("Job %d finished, status=%s"), job->m_id, (job->m_status == JOB_COMPLETED) ? _T("COMPLETED") : ((job->m_status == JOB_CANCEL_PENDING) ? _T("CANCELLED") : _T("FAILED")));
ab621f39 164
129a1ce0
VK
165 if (job->m_owningQueue != NULL)
166 job->m_owningQueue->jobCompleted(job);
ab621f39
VK
167 return THREAD_OK;
168}
169
170
171//
172// Start job
173//
174
175void ServerJob::start()
176{
177 m_status = JOB_ACTIVE;
178 m_workerThread = ThreadCreateEx(WorkerThreadStarter, 0, this);
179}
180
181
182//
183// Cancel job
184//
185
186bool ServerJob::cancel()
187{
f40831eb
VK
188 switch(m_status)
189 {
190 case JOB_COMPLETED:
f2665675 191 case JOB_CANCEL_PENDING:
f40831eb
VK
192 return false;
193 case JOB_ACTIVE:
f2665675
VK
194 if (!onCancel())
195 return false;
196 changeStatus(JOB_CANCEL_PENDING);
197 return true;
f40831eb 198 default:
3929b1ca 199 changeStatus(JOB_CANCELLED);
f40831eb
VK
200 return true;
201 }
ab621f39
VK
202}
203
204
205//
206// Default run (empty)
207//
208
209bool ServerJob::run()
210{
211 return true;
212}
213
214
215//
216// Default cancel handler
217//
218
219bool ServerJob::onCancel()
220{
221 return false;
222}
223
224
225//
226// Set failure message
227//
228
229void ServerJob::setFailureMessage(const TCHAR *msg)
230{
231 safe_free(m_failureMessage);
232 m_failureMessage = (msg != NULL) ? _tcsdup(msg) : NULL;
233}
3929b1ca
VK
234
235
236//
237// Set description
238//
239
240void ServerJob::setDescription(const TCHAR *description)
241{
242 safe_free(m_description);
243 m_description = _tcsdup(description);
244}
245
246
247//
248// Fill NXCP message with job's data
249//
250
251void ServerJob::fillMessage(CSCPMessage *msg)
252{
253 msg->SetVariable(VID_JOB_ID, m_id);
0edd0ab0 254 msg->SetVariable(VID_USER_ID, m_userId);
3929b1ca
VK
255 msg->SetVariable(VID_JOB_TYPE, m_type);
256 msg->SetVariable(VID_OBJECT_ID, m_remoteNode);
257 msg->SetVariable(VID_DESCRIPTION, CHECK_NULL_EX(m_description));
258 msg->SetVariable(VID_JOB_STATUS, (WORD)m_status);
259 msg->SetVariable(VID_JOB_PROGRESS, (WORD)m_progress);
8134d3a3
VK
260 if (m_status == JOB_FAILED)
261 msg->SetVariable(VID_FAILURE_MESSAGE, m_failureMessage != NULL ? m_failureMessage : _T("Internal error"));
262 else
263 msg->SetVariable(VID_FAILURE_MESSAGE, CHECK_NULL_EX(m_failureMessage));
3929b1ca 264}