1 /******************************************************************************
3 * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
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. *
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. *
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 ******************************************************************************/
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"
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>
40 using namespace icinga;
42 REGISTER_TYPE(DynamicObject);
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;
50 DynamicObject::DynamicObject(void)
53 DynamicType::Ptr DynamicObject::GetType(void) const
55 return DynamicType::GetByName(GetTypeName());
58 DebugInfo DynamicObject::GetDebugInfo(void) const
63 void DynamicObject::SetDebugInfo(const DebugInfo& di)
68 bool DynamicObject::IsActive(void) const
73 bool DynamicObject::IsPaused(void) const
78 void DynamicObject::SetExtension(const String& key, const Object::Ptr& object)
80 Dictionary::Ptr extensions = GetExtensions();
83 extensions = make_shared<Dictionary>();
84 SetExtensions(extensions);
87 extensions->Set(key, object);
90 Object::Ptr DynamicObject::GetExtension(const String& key)
92 Dictionary::Ptr extensions = GetExtensions();
97 return extensions->Get(key);
100 void DynamicObject::ClearExtension(const String& key)
102 Dictionary::Ptr extensions = GetExtensions();
107 extensions->Remove(key);
110 void DynamicObject::Register(void)
114 DynamicType::Ptr dtype = GetType();
115 dtype->RegisterObject(GetSelf());
118 void DynamicObject::Start(void)
121 ObjectLock olock(this);
123 SetStartCalled(true);
126 void DynamicObject::Activate(void)
132 ASSERT(GetStartCalled());
135 ObjectLock olock(this);
140 OnStarted(GetSelf());
145 void DynamicObject::Stop(void)
148 ObjectLock olock(this);
153 void DynamicObject::Deactivate(void)
160 ObjectLock olock(this);
170 ASSERT(GetStopCalled());
172 OnStopped(GetSelf());
175 void DynamicObject::OnConfigLoaded(void)
177 /* Nothing to do here. */
180 void DynamicObject::OnStateLoaded(void)
182 /* Nothing to do here. */
185 void DynamicObject::Pause(void)
187 SetPauseCalled(true);
190 void DynamicObject::Resume(void)
192 SetResumeCalled(true);
195 void DynamicObject::SetAuthority(bool authority)
197 if (authority && GetPaused()) {
198 SetResumeCalled(false);
200 ASSERT(GetResumeCalled());
202 OnResumed(GetSelf());
203 } else if (!authority && !GetPaused()) {
204 SetPauseCalled(false);
206 ASSERT(GetPauseCalled());
212 Value DynamicObject::InvokeMethod(const String& method,
213 const std::vector<Value>& arguments)
215 Dictionary::Ptr methods;
217 methods = GetMethods();
220 BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
222 Value funcName = methods->Get(method);
224 if (funcName.IsEmpty())
225 BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
227 ScriptFunction::Ptr func;
229 if (funcName.IsObjectType<ScriptFunction>()) {
232 func = ScriptFunction::GetByName(funcName);
235 BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + String(funcName) + "' does not exist."));
238 return func->Invoke(arguments);
241 void DynamicObject::DumpObjects(const String& filename, int attributeTypes)
243 Log(LogInformation, "DynamicObject")
244 << "Dumping program state to file '" << filename << "'";
246 String tempFilename = filename + ".tmp";
249 fp.open(tempFilename.CStr(), std::ios_base::out);
252 BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
254 StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
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>();
260 persistentObject->Set("type", type->GetName());
261 persistentObject->Set("name", object->GetName());
263 Dictionary::Ptr update = Serialize(object, attributeTypes);
268 persistentObject->Set("update", update);
270 String json = JsonEncode(persistentObject);
272 NetString::WriteStringToStream(sfp, json);
281 _unlink(filename.CStr());
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));
292 void DynamicObject::RestoreObject(const String& message, int attributeTypes)
294 Dictionary::Ptr persistentObject = JsonDecode(message);
296 String type = persistentObject->Get("type");
298 DynamicType::Ptr dt = DynamicType::GetByName(type);
303 String name = persistentObject->Get("name");
305 DynamicObject::Ptr object = dt->GetObject(name);
310 ASSERT(!object->IsActive());
312 Log(LogDebug, "DynamicObject")
313 << "Restoring object '" << name << "' of type '" << type << "'.";
315 Dictionary::Ptr update = persistentObject->Get("update");
316 Deserialize(object, update, false, attributeTypes);
317 object->OnStateLoaded();
320 void DynamicObject::RestoreObjects(const String& filename, int attributeTypes)
322 Log(LogInformation, "DynamicObject")
323 << "Restoring program state from file '" << filename << "'";
326 fp.open(filename.CStr(), std::ios_base::in);
328 StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
330 unsigned long restored = 0;
332 ParallelWorkQueue upq;
335 while (NetString::ReadStringFromStream(sfp, &message)) {
336 upq.Enqueue(boost::bind(&DynamicObject::RestoreObject, message, attributeTypes));
344 Log(LogInformation, "DynamicObject")
345 << "Restored " << restored << " objects";
348 void DynamicObject::StopObjects(void)
350 BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
351 BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
352 object->Deactivate();
357 DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name)
359 DynamicType::Ptr dtype = DynamicType::GetByName(type);
360 return dtype->GetObject(name);