]> granicus.if.org Git - icinga2/blob - lib/base/dynamicobject.cpp
Replace cJSON with YAJL
[icinga2] / lib / base / dynamicobject.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (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 Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "base/dynamicobject.hpp"
21 #include "base/dynamictype.hpp"
22 #include "base/serializer.hpp"
23 #include "base/netstring.hpp"
24 #include "base/json.hpp"
25 #include "base/stdiostream.hpp"
26 #include "base/debug.hpp"
27 #include "base/objectlock.hpp"
28 #include "base/logger.hpp"
29 #include "base/exception.hpp"
30 #include "base/scriptfunction.hpp"
31 #include "base/initialize.hpp"
32 #include "base/scriptvariable.hpp"
33 #include "base/workqueue.hpp"
34 #include <fstream>
35 #include <boost/foreach.hpp>
36 #include <boost/exception/errinfo_api_function.hpp>
37 #include <boost/exception/errinfo_errno.hpp>
38 #include <boost/exception/errinfo_file_name.hpp>
39
40 using namespace icinga;
41
42 REGISTER_TYPE(DynamicObject);
43
44 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStarted;
45 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStopped;
46 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnPaused;
47 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnResumed;
48 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStateChanged;
49
50 DynamicObject::DynamicObject(void)
51 { }
52
53 DynamicType::Ptr DynamicObject::GetType(void) const
54 {
55         return DynamicType::GetByName(GetTypeName());
56 }
57
58 DebugInfo DynamicObject::GetDebugInfo(void) const
59 {
60         return m_DebugInfo;
61 }
62
63 void DynamicObject::SetDebugInfo(const DebugInfo& di)
64 {
65         m_DebugInfo = di;
66 }
67
68 bool DynamicObject::IsActive(void) const
69 {
70         return GetActive();
71 }
72
73 bool DynamicObject::IsPaused(void) const
74 {
75         return GetPaused();
76 }
77
78 void DynamicObject::SetExtension(const String& key, const Object::Ptr& object)
79 {
80         Dictionary::Ptr extensions = GetExtensions();
81
82         if (!extensions) {
83                 extensions = make_shared<Dictionary>();
84                 SetExtensions(extensions);
85         }
86
87         extensions->Set(key, object);
88 }
89
90 Object::Ptr DynamicObject::GetExtension(const String& key)
91 {
92         Dictionary::Ptr extensions = GetExtensions();
93
94         if (!extensions)
95                 return Object::Ptr();
96
97         return extensions->Get(key);
98 }
99
100 void DynamicObject::ClearExtension(const String& key)
101 {
102         Dictionary::Ptr extensions = GetExtensions();
103
104         if (!extensions)
105                 return;
106
107         extensions->Remove(key);
108 }
109
110 void DynamicObject::Register(void)
111 {
112         ASSERT(!OwnsLock());
113
114         DynamicType::Ptr dtype = GetType();
115         dtype->RegisterObject(GetSelf());
116 }
117
118 void DynamicObject::Start(void)
119 {
120         ASSERT(!OwnsLock());
121         ObjectLock olock(this);
122
123         SetStartCalled(true);
124 }
125
126 void DynamicObject::Activate(void)
127 {
128         ASSERT(!OwnsLock());
129
130         Start();
131
132         ASSERT(GetStartCalled());
133
134         {
135                 ObjectLock olock(this);
136                 ASSERT(!IsActive());
137                 SetActive(true);
138         }
139
140         OnStarted(GetSelf());
141
142         SetAuthority(true);
143 }
144
145 void DynamicObject::Stop(void)
146 {
147         ASSERT(!OwnsLock());
148         ObjectLock olock(this);
149
150         SetStopCalled(true);
151 }
152
153 void DynamicObject::Deactivate(void)
154 {
155         ASSERT(!OwnsLock());
156
157         SetAuthority(false);
158
159         {
160                 ObjectLock olock(this);
161
162                 if (!IsActive())
163                         return;
164
165                 SetActive(false);
166         }
167
168         Stop();
169
170         ASSERT(GetStopCalled());
171
172         OnStopped(GetSelf());
173 }
174
175 void DynamicObject::OnConfigLoaded(void)
176 {
177         /* Nothing to do here. */
178 }
179
180 void DynamicObject::OnStateLoaded(void)
181 {
182         /* Nothing to do here. */
183 }
184
185 void DynamicObject::Pause(void)
186 {
187         SetPauseCalled(true);
188 }
189
190 void DynamicObject::Resume(void)
191 {
192         SetResumeCalled(true);
193 }
194
195 void DynamicObject::SetAuthority(bool authority)
196 {
197         if (authority && GetPaused()) {
198                 SetResumeCalled(false);
199                 Resume();
200                 ASSERT(GetResumeCalled());
201                 SetPaused(false);
202                 OnResumed(GetSelf());
203         } else if (!authority && !GetPaused()) {
204                 SetPauseCalled(false);
205                 Pause();
206                 ASSERT(GetPauseCalled());
207                 SetPaused(true);
208                 OnPaused(GetSelf());
209         }
210 }
211
212 Value DynamicObject::InvokeMethod(const String& method,
213     const std::vector<Value>& arguments)
214 {
215         Dictionary::Ptr methods;
216
217         methods = GetMethods();
218
219         if (!methods)
220                 BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
221
222         Value funcName = methods->Get(method);
223
224         if (funcName.IsEmpty())
225                 BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
226
227         ScriptFunction::Ptr func;
228
229         if (funcName.IsObjectType<ScriptFunction>()) {
230                 func = funcName;
231         } else {
232                 func = ScriptFunction::GetByName(funcName);
233
234                 if (!func)
235                         BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + String(funcName) + "' does not exist."));
236         }
237
238         return func->Invoke(arguments);
239 }
240
241 void DynamicObject::DumpObjects(const String& filename, int attributeTypes)
242 {
243         Log(LogInformation, "DynamicObject")
244             << "Dumping program state to file '" << filename << "'";
245
246         String tempFilename = filename + ".tmp";
247
248         std::fstream fp;
249         fp.open(tempFilename.CStr(), std::ios_base::out);
250
251         if (!fp)
252                 BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
253
254         StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
255
256         BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
257                 BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
258                         Dictionary::Ptr persistentObject = make_shared<Dictionary>();
259
260                         persistentObject->Set("type", type->GetName());
261                         persistentObject->Set("name", object->GetName());
262
263                         Dictionary::Ptr update = Serialize(object, attributeTypes);
264
265                         if (!update)
266                                 continue;
267
268                         persistentObject->Set("update", update);
269
270                         String json = JsonEncode(persistentObject);
271
272                         NetString::WriteStringToStream(sfp, json);
273                 }
274         }
275
276         sfp->Close();
277
278         fp.close();
279
280 #ifdef _WIN32
281         _unlink(filename.CStr());
282 #endif /* _WIN32 */
283
284         if (rename(tempFilename.CStr(), filename.CStr()) < 0) {
285                 BOOST_THROW_EXCEPTION(posix_error()
286                     << boost::errinfo_api_function("rename")
287                     << boost::errinfo_errno(errno)
288                     << boost::errinfo_file_name(tempFilename));
289         }
290 }
291
292 void DynamicObject::RestoreObject(const String& message, int attributeTypes)
293 {
294         Dictionary::Ptr persistentObject = JsonDecode(message);
295
296         String type = persistentObject->Get("type");
297
298         DynamicType::Ptr dt = DynamicType::GetByName(type);
299
300         if (!dt)
301                 return;
302
303         String name = persistentObject->Get("name");
304
305         DynamicObject::Ptr object = dt->GetObject(name);
306
307         if (!object)
308                 return;
309
310         ASSERT(!object->IsActive());
311 #ifdef _DEBUG
312         Log(LogDebug, "DynamicObject")
313             << "Restoring object '" << name << "' of type '" << type << "'.";
314 #endif /* _DEBUG */
315         Dictionary::Ptr update = persistentObject->Get("update");
316         Deserialize(object, update, false, attributeTypes);
317         object->OnStateLoaded();
318 }
319
320 void DynamicObject::RestoreObjects(const String& filename, int attributeTypes)
321 {
322         Log(LogInformation, "DynamicObject")
323             << "Restoring program state from file '" << filename << "'";
324
325         std::fstream fp;
326         fp.open(filename.CStr(), std::ios_base::in);
327
328         StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
329
330         unsigned long restored = 0;
331
332         ParallelWorkQueue upq;
333
334         String message;
335         while (NetString::ReadStringFromStream(sfp, &message)) {
336                 upq.Enqueue(boost::bind(&DynamicObject::RestoreObject, message, attributeTypes));
337                 restored++;
338         }
339
340         sfp->Close();
341
342         upq.Join();
343
344         Log(LogInformation, "DynamicObject")
345             << "Restored " << restored << " objects";
346 }
347
348 void DynamicObject::StopObjects(void)
349 {
350         BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
351                 BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
352                         object->Deactivate();
353                 }
354         }
355 }
356
357 DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name)
358 {
359         DynamicType::Ptr dtype = DynamicType::GetByName(type);
360         return dtype->GetObject(name);
361 }