1 /******************************************************************************
3 * Copyright (C) 2012-2015 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/function.hpp"
31 #include "base/initialize.hpp"
32 #include "base/workqueue.hpp"
33 #include "base/context.hpp"
34 #include "base/application.hpp"
36 #include <boost/foreach.hpp>
37 #include <boost/exception/errinfo_api_function.hpp>
38 #include <boost/exception/errinfo_errno.hpp>
39 #include <boost/exception/errinfo_file_name.hpp>
41 using namespace icinga;
43 REGISTER_TYPE(DynamicObject);
45 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStarted;
46 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStopped;
47 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnPaused;
48 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnResumed;
49 boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStateChanged;
51 DynamicObject::DynamicObject(void)
54 DynamicType::Ptr DynamicObject::GetType(void) const
56 return DynamicType::GetByName(GetTypeNameV());
59 DebugInfo DynamicObject::GetDebugInfo(void) const
64 void DynamicObject::SetDebugInfo(const DebugInfo& di)
69 bool DynamicObject::IsActive(void) const
74 bool DynamicObject::IsPaused(void) const
79 void DynamicObject::SetExtension(const String& key, const Value& value)
81 Dictionary::Ptr extensions = GetExtensions();
84 extensions = new Dictionary();
85 SetExtensions(extensions);
88 extensions->Set(key, value);
91 Value DynamicObject::GetExtension(const String& key)
93 Dictionary::Ptr extensions = GetExtensions();
98 return extensions->Get(key);
101 void DynamicObject::ClearExtension(const String& key)
103 Dictionary::Ptr extensions = GetExtensions();
108 extensions->Remove(key);
111 void DynamicObject::Register(void)
115 DynamicType::Ptr dtype = GetType();
116 dtype->RegisterObject(this);
119 void DynamicObject::Start(void)
122 ObjectLock olock(this);
124 SetStartCalled(true);
127 void DynamicObject::Activate(void)
129 CONTEXT("Activating object '" + GetName() + "' of type '" + GetType()->GetName() + "'");
135 ASSERT(GetStartCalled());
138 ObjectLock olock(this);
148 void DynamicObject::Stop(void)
151 ObjectLock olock(this);
156 void DynamicObject::Deactivate(void)
158 CONTEXT("Deactivating object '" + GetName() + "' of type '" + GetType()->GetName() + "'");
165 ObjectLock olock(this);
175 ASSERT(GetStopCalled());
180 void DynamicObject::OnConfigLoaded(void)
182 /* Nothing to do here. */
185 void DynamicObject::OnAllConfigLoaded(void)
187 /* Nothing to do here. */
190 void DynamicObject::OnStateLoaded(void)
192 /* Nothing to do here. */
195 void DynamicObject::Pause(void)
197 SetPauseCalled(true);
200 void DynamicObject::Resume(void)
202 SetResumeCalled(true);
205 void DynamicObject::SetAuthority(bool authority)
207 if (authority && GetPaused()) {
208 SetResumeCalled(false);
210 ASSERT(GetResumeCalled());
213 } else if (!authority && !GetPaused()) {
214 SetPauseCalled(false);
216 ASSERT(GetPauseCalled());
222 void DynamicObject::DumpObjects(const String& filename, int attributeTypes)
224 Log(LogInformation, "DynamicObject")
225 << "Dumping program state to file '" << filename << "'";
227 String tempFilename = filename + ".tmp";
230 fp.open(tempFilename.CStr(), std::ios_base::out);
233 BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
235 StdioStream::Ptr sfp = new StdioStream(&fp, false);
237 BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
238 BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
239 Dictionary::Ptr persistentObject = new Dictionary();
241 persistentObject->Set("type", type->GetName());
242 persistentObject->Set("name", object->GetName());
244 Dictionary::Ptr update = Serialize(object, attributeTypes);
249 persistentObject->Set("update", update);
251 String json = JsonEncode(persistentObject);
253 NetString::WriteStringToStream(sfp, json);
262 _unlink(filename.CStr());
265 if (rename(tempFilename.CStr(), filename.CStr()) < 0) {
266 BOOST_THROW_EXCEPTION(posix_error()
267 << boost::errinfo_api_function("rename")
268 << boost::errinfo_errno(errno)
269 << boost::errinfo_file_name(tempFilename));
273 void DynamicObject::RestoreObject(const String& message, int attributeTypes)
275 Dictionary::Ptr persistentObject = JsonDecode(message);
277 String type = persistentObject->Get("type");
279 DynamicType::Ptr dt = DynamicType::GetByName(type);
284 String name = persistentObject->Get("name");
286 DynamicObject::Ptr object = dt->GetObject(name);
291 ASSERT(!object->IsActive());
293 Log(LogDebug, "DynamicObject")
294 << "Restoring object '" << name << "' of type '" << type << "'.";
295 #endif /* I2_DEBUG */
296 Dictionary::Ptr update = persistentObject->Get("update");
297 Deserialize(object, update, false, attributeTypes);
298 object->OnStateLoaded();
299 object->SetStateLoaded(true);
302 void DynamicObject::RestoreObjects(const String& filename, int attributeTypes)
304 if (!Utility::PathExists(filename))
307 Log(LogInformation, "DynamicObject")
308 << "Restoring program state from file '" << filename << "'";
311 fp.open(filename.CStr(), std::ios_base::in);
313 StdioStream::Ptr sfp = new StdioStream (&fp, false);
315 unsigned long restored = 0;
317 WorkQueue upq(25000, Application::GetConcurrency());
320 StreamReadContext src;
322 StreamReadStatus srs = NetString::ReadStringFromStream(sfp, &message, src);
324 if (srs == StatusEof)
327 if (srs != StatusNewItem)
330 upq.Enqueue(boost::bind(&DynamicObject::RestoreObject, message, attributeTypes));
338 unsigned long no_state = 0;
340 BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
341 BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
342 if (!object->GetStateLoaded()) {
343 object->OnStateLoaded();
344 object->SetStateLoaded(true);
351 Log(LogInformation, "DynamicObject")
352 << "Restored " << restored << " objects. Loaded " << no_state << " new objects without state.";
355 void DynamicObject::StopObjects(void)
357 BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
358 BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
359 object->Deactivate();
364 DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name)
366 DynamicType::Ptr dtype = DynamicType::GetByName(type);
367 return dtype->GetObject(name);