From 83772d4386926e1ee3ad11e778a929d525c029f1 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 4 Dec 2012 08:42:24 +0100 Subject: [PATCH] Implemented DynamicType support. Fixes #3477 --- components/compat/compatcomponent.cpp | 4 +- components/compatido/compatidocomponent.cpp | 8 +- components/delegation/delegationcomponent.cpp | 6 +- .../replication/replicationcomponent.cpp | 12 +- lib/base/Makefile.am | 2 + lib/base/application.cpp | 2 +- lib/base/base.vcxproj | 2 + lib/base/base.vcxproj.filters | 6 + lib/base/component.cpp | 2 +- lib/base/dynamicobject.cpp | 130 ++++-------------- lib/base/dynamicobject.h | 51 +------ lib/base/dynamictype.cpp | 118 ++++++++++++++++ lib/base/dynamictype.h | 110 +++++++++++++++ lib/base/i2-base.h | 1 + lib/base/logger.cpp | 16 ++- lib/base/object.cpp | 68 ++++++--- lib/base/object.h | 13 +- lib/base/socket.cpp | 3 + lib/base/tlsstream.cpp | 3 + lib/config/configitem.cpp | 6 +- lib/icinga/host.cpp | 10 +- lib/icinga/hostgroup.cpp | 8 +- lib/icinga/icingaapplication.cpp | 16 ++- lib/icinga/icingaapplication.h | 2 - lib/icinga/service.cpp | 48 +++---- lib/icinga/servicegroup.cpp | 8 +- lib/remoting/endpoint.cpp | 18 +-- lib/remoting/endpointmanager.cpp | 15 +- lib/remoting/endpointmanager.h | 1 + 29 files changed, 440 insertions(+), 249 deletions(-) create mode 100644 lib/base/dynamictype.cpp create mode 100644 lib/base/dynamictype.h diff --git a/components/compat/compatcomponent.cpp b/components/compat/compatcomponent.cpp index 45bd28f64..2faa003d8 100644 --- a/components/compat/compatcomponent.cpp +++ b/components/compat/compatcomponent.cpp @@ -248,7 +248,7 @@ void CompatComponent::StatusTimerHandler(void) map > hostgroups; DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Host")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Host")->GetObjects()) { const Host::Ptr& host = static_pointer_cast(object); Dictionary::Ptr dict; @@ -290,7 +290,7 @@ void CompatComponent::StatusTimerHandler(void) map > servicegroups; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Service")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) { Service::Ptr service = static_pointer_cast(object); Dictionary::Ptr dict; diff --git a/components/compatido/compatidocomponent.cpp b/components/compatido/compatidocomponent.cpp index c680ba1b8..a1113bd0b 100644 --- a/components/compatido/compatidocomponent.cpp +++ b/components/compatido/compatidocomponent.cpp @@ -740,7 +740,7 @@ void CompatIdoComponent::DumpConfigObjects(void) map > hostgroups; DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Host")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Host")->GetObjects()) { const Host::Ptr& host = static_pointer_cast(object); Dictionary::Ptr dict; @@ -785,7 +785,7 @@ void CompatIdoComponent::DumpConfigObjects(void) /* services and servicegroups */ map > servicegroups; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Service")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) { Service::Ptr service = static_pointer_cast(object); Dictionary::Ptr dict; @@ -854,7 +854,7 @@ void CompatIdoComponent::DumpStatusData(void) { /* hosts */ DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Host")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Host")->GetObjects()) { const Host::Ptr& host = static_pointer_cast(object); DumpHostStatus(host); @@ -862,7 +862,7 @@ void CompatIdoComponent::DumpStatusData(void) /* services */ - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Service")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) { Service::Ptr service = static_pointer_cast(object); DumpServiceStatus(service); diff --git a/components/delegation/delegationcomponent.cpp b/components/delegation/delegationcomponent.cpp index 9e8e85a03..7dff383d2 100644 --- a/components/delegation/delegationcomponent.cpp +++ b/components/delegation/delegationcomponent.cpp @@ -41,7 +41,7 @@ vector DelegationComponent::GetCheckerCandidates(const Service::P vector candidates; DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Endpoint")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) { Endpoint::Ptr endpoint = dynamic_pointer_cast(object); String myIdentity = EndpointManager::GetInstance()->GetIdentity(); @@ -73,7 +73,7 @@ void DelegationComponent::DelegationTimerHandler(void) map histogram; DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Endpoint")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) { Endpoint::Ptr endpoint = dynamic_pointer_cast(object); histogram[endpoint] = 0; @@ -82,7 +82,7 @@ void DelegationComponent::DelegationTimerHandler(void) vector services; /* build "checker -> service count" histogram */ - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Service")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) { Service::Ptr service = dynamic_pointer_cast(object); if (!service) diff --git a/components/replication/replicationcomponent.cpp b/components/replication/replicationcomponent.cpp index 06ca0c8a1..f8ee5c68c 100644 --- a/components/replication/replicationcomponent.cpp +++ b/components/replication/replicationcomponent.cpp @@ -85,11 +85,10 @@ void ReplicationComponent::EndpointConnectedHandler(const Endpoint::Ptr& endpoin endpoint->RegisterSubscription("config::ObjectUpdate"); endpoint->RegisterSubscription("config::ObjectRemoved"); - pair trange = DynamicObject::GetTypes(); - DynamicObject::TypeMap::iterator tt; - for (tt = trange.first; tt != trange.second; tt++) { + DynamicType::Ptr type; + BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) { DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), tt->second) { + BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) { if (!ShouldReplicateObject(object)) continue; @@ -186,12 +185,13 @@ void ReplicationComponent::RemoteObjectUpdateHandler(const Endpoint::Ptr& sender if (!params.Get("update", &update)) return; - DynamicObject::Ptr object = DynamicObject::GetObject(type, name); + DynamicType::Ptr dtype = DynamicType::GetByName(type); + DynamicObject::Ptr object = dtype->GetObject(name); // TODO: sanitize update, disallow __local if (!object) { - object = DynamicObject::Create(type, update); + object = dtype->CreateObject(update); if (source == EndpointManager::GetInstance()->GetIdentity()) { /* the peer sent us an object that was originally created by us - diff --git a/lib/base/Makefile.am b/lib/base/Makefile.am index 5df39cb42..575a83546 100644 --- a/lib/base/Makefile.am +++ b/lib/base/Makefile.am @@ -16,6 +16,8 @@ libbase_la_SOURCES = \ dictionary.h \ dynamicobject.cpp \ dynamicobject.h \ + dynamictype.cpp \ + dynamictype.h \ event.cpp \ event.h \ exception.cpp \ diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 42b72a421..23dac5ed9 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -122,7 +122,7 @@ void Application::RunEventLoop(void) #ifdef _DEBUG if (nextProfile < Utility::GetTime()) { stringstream msgbuf; - msgbuf << "Active objects: " << Object::GetAliveObjects(); + msgbuf << "Active objects: " << Object::GetAliveObjectsCount(); Logger::Write(LogInformation, "base", msgbuf.str()); Object::PrintMemoryProfile(); diff --git a/lib/base/base.vcxproj b/lib/base/base.vcxproj index 233c6bfeb..47253afa4 100644 --- a/lib/base/base.vcxproj +++ b/lib/base/base.vcxproj @@ -24,6 +24,7 @@ + @@ -61,6 +62,7 @@ + diff --git a/lib/base/base.vcxproj.filters b/lib/base/base.vcxproj.filters index 912b4fe92..af7b4337a 100644 --- a/lib/base/base.vcxproj.filters +++ b/lib/base/base.vcxproj.filters @@ -88,6 +88,9 @@ Quelldateien + + Quelldateien + @@ -186,6 +189,9 @@ Headerdateien + + Headerdateien + diff --git a/lib/base/component.cpp b/lib/base/component.cpp index bc66042c6..cf8413e7b 100644 --- a/lib/base/component.cpp +++ b/lib/base/component.cpp @@ -24,7 +24,7 @@ using namespace icinga; -REGISTER_CLASS(Component); +REGISTER_TYPE(Component, NULL); /** * Constructor for the component class. diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 7be1d424f..9b50c42cf 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -219,9 +219,10 @@ void DynamicObject::ClearAttributesByType(DynamicAttributeType type) } } -String DynamicObject::GetType(void) const +DynamicType::Ptr DynamicObject::GetType(void) const { - return Get("__type"); + String name = Get("__type"); + return DynamicType::GetByName(name); } String DynamicObject::GetName(void) const @@ -263,13 +264,11 @@ void DynamicObject::Register(void) { assert(Application::IsMainThread()); - DynamicObject::Ptr dobj = GetObject(GetType(), GetName()); + DynamicObject::Ptr dobj = GetType()->GetObject(GetName()); DynamicObject::Ptr self = GetSelf(); assert(!dobj || dobj == self); - pair ti; - ti = GetAllObjects().insert(make_pair(GetType(), DynamicObject::NameMap())); - ti.first->second.insert(make_pair(GetName(), GetSelf())); + GetType()->RegisterObject(self); OnRegistered(GetSelf()); @@ -285,51 +284,14 @@ void DynamicObject::Unregister(void) { assert(Application::IsMainThread()); - DynamicObject::TypeMap::iterator tt; - tt = GetAllObjects().find(GetType()); - - if (tt == GetAllObjects().end()) - return; - - DynamicObject::NameMap::iterator nt = tt->second.find(GetName()); - - if (nt == tt->second.end()) + if (GetType()->GetObject(GetName())) return; - tt->second.erase(nt); + GetType()->UnregisterObject(GetSelf()); OnUnregistered(GetSelf()); } -DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name) -{ - DynamicObject::TypeMap::iterator tt; - tt = GetAllObjects().find(type); - - if (tt == GetAllObjects().end()) - return DynamicObject::Ptr(); - - DynamicObject::NameMap::iterator nt = tt->second.find(name); - - if (nt == tt->second.end()) - return DynamicObject::Ptr(); - - return nt->second; -} - -pair DynamicObject::GetTypes(void) -{ - return make_pair(GetAllObjects().begin(), GetAllObjects().end()); -} - -pair DynamicObject::GetObjects(const String& type) -{ - pair ti; - ti = GetAllObjects().insert(make_pair(type, DynamicObject::NameMap())); - - return make_pair(ti.first->second.begin(), ti.first->second.end()); -} - ScriptTask::Ptr DynamicObject::InvokeMethod(const String& method, const vector& arguments, ScriptTask::CompletionCallback callback) { @@ -370,12 +332,10 @@ void DynamicObject::DumpObjects(const String& filename) StdioStream::Ptr sfp = boost::make_shared(&fp, false); sfp->Start(); - DynamicObject::TypeMap::iterator tt; - for (tt = GetAllObjects().begin(); tt != GetAllObjects().end(); tt++) { - DynamicObject::NameMap::iterator nt; - for (nt = tt->second.begin(); nt != tt->second.end(); nt++) { - DynamicObject::Ptr object = nt->second; - + DynamicType::Ptr type; + BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) { + DynamicObject::Ptr object; + BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) { if (object->IsLocal()) continue; @@ -449,10 +409,15 @@ void DynamicObject::RestoreObjects(const String& filename) bool hasConfig = update->Contains("configTx"); - DynamicObject::Ptr object = GetObject(type, name); + DynamicType::Ptr dt = DynamicType::GetByName(type); + + if (!dt) + throw_exception(invalid_argument("Invalid type: " + type)); + + DynamicObject::Ptr object = dt->GetObject(name); if (hasConfig && !object) { - object = Create(type, update); + object = dt->CreateObject(update); object->Register(); } else if (object) { object->ApplyUpdate(update, Attribute_All); @@ -464,11 +429,11 @@ void DynamicObject::RestoreObjects(const String& filename) void DynamicObject::DeactivateObjects(void) { - DynamicObject::TypeMap::iterator tt; - for (tt = GetAllObjects().begin(); tt != GetAllObjects().end(); tt++) { - DynamicObject::NameMap::iterator nt; + DynamicType::TypeMap::iterator tt; + for (tt = DynamicType::GetTypes().begin(); tt != DynamicType::GetTypes().end(); tt++) { + DynamicType::NameMap::iterator nt; - while ((nt = tt->second.begin()) != tt->second.end()) { + while ((nt = tt->second->GetObjects().begin()) != tt->second->GetObjects().end()) { DynamicObject::Ptr object = nt->second; object->Unregister(); @@ -476,52 +441,6 @@ void DynamicObject::DeactivateObjects(void) } } -DynamicObject::TypeMap& DynamicObject::GetAllObjects(void) -{ - static TypeMap objects; - return objects; -} - -DynamicObject::ClassMap& DynamicObject::GetClasses(void) -{ - static ClassMap classes; - return classes; -} - -bool DynamicObject::ClassExists(const String& name) -{ - return (GetClasses().find(name) != GetClasses().end()); -} - -void DynamicObject::RegisterClass(const String& type, DynamicObject::Factory factory) -{ - if (GetObjects(type).first != GetObjects(type).second) - throw_exception(runtime_error("Cannot register class for type '" + - type + "': Objects of this type already exist.")); - - GetClasses()[type] = factory; -} - -DynamicObject::Ptr DynamicObject::Create(const String& type, const Dictionary::Ptr& serializedUpdate) -{ - DynamicObject::ClassMap::iterator ct; - ct = GetClasses().find(type); - - DynamicObject::Ptr obj; - if (ct != GetClasses().end()) { - obj = ct->second(serializedUpdate); - } else { - obj = boost::make_shared(serializedUpdate); - - Logger::Write(LogCritical, "base", "Creating generic DynamicObject for type '" + type + "'"); - } - - /* apply the object's non-config attributes */ - obj->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config); - - return obj; -} - double DynamicObject::GetCurrentTx(void) { assert(m_CurrentTx != 0); @@ -545,3 +464,8 @@ void DynamicObject::FinishTx(void) void DynamicObject::OnAttributeChanged(const String&, const Value&) { } +DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name) +{ + DynamicType::Ptr dtype = DynamicType::GetByName(type); + return dtype->GetObject(name); +} diff --git a/lib/base/dynamicobject.h b/lib/base/dynamicobject.h index e7f4814db..828622da9 100644 --- a/lib/base/dynamicobject.h +++ b/lib/base/dynamicobject.h @@ -60,6 +60,8 @@ struct DynamicAttribute double Tx; /**< The timestamp of the last value change. */ }; +class DynamicType; + /** * A dynamic object that can be instantiated from the configuration file * and that supports attribute replication to remote application instances. @@ -72,12 +74,6 @@ public: typedef shared_ptr Ptr; typedef weak_ptr WeakPtr; - typedef function Factory; - - typedef map ClassMap; - typedef map NameMap; - typedef map TypeMap; - typedef map AttributeMap; typedef AttributeMap::iterator AttributeIterator; typedef AttributeMap::const_iterator AttributeConstIterator; @@ -104,7 +100,7 @@ public: ScriptTask::Ptr InvokeMethod(const String& method, const vector& arguments, ScriptTask::CompletionCallback callback); - String GetType(void) const; + shared_ptr GetType(void) const; String GetName(void) const; bool IsLocal(void) const; @@ -122,17 +118,11 @@ public: virtual void Start(void); static DynamicObject::Ptr GetObject(const String& type, const String& name); - static pair GetTypes(void); - static pair GetObjects(const String& type); static void DumpObjects(const String& filename); static void RestoreObjects(const String& filename); static void DeactivateObjects(void); - static void RegisterClass(const String& type, Factory factory); - static bool ClassExists(const String& type); - static DynamicObject::Ptr Create(const String& type, const Dictionary::Ptr& serializedUpdate); - static double GetCurrentTx(void); static void BeginTx(void); static void FinishTx(void); @@ -144,9 +134,6 @@ private: void InternalSetAttribute(const String& name, const Value& data, double tx, bool suppressEvent = false); Value InternalGetAttribute(const String& name) const; - static ClassMap& GetClasses(void); - static TypeMap& GetAllObjects(void); - AttributeMap m_Attributes; double m_ConfigTx; @@ -157,38 +144,6 @@ private: void InternalApplyUpdate(const Dictionary::Ptr& serializedUpdate, int allowedTypes, bool suppressEvents); }; -/** - * Helper class for registering DynamicObject implementation classes. - * - * @ingroup base - */ -class RegisterClassHelper -{ -public: - RegisterClassHelper(const String& name, DynamicObject::Factory factory) - { - if (!DynamicObject::ClassExists(name)) - DynamicObject::RegisterClass(name, factory); - } -}; - -/** - * Factory function for DynamicObject-based classes. - * - * @ingroup base - */ -template -shared_ptr DynamicObjectFactory(const Dictionary::Ptr& serializedUpdate) -{ - return boost::make_shared(serializedUpdate); -} - -#define REGISTER_CLASS_ALIAS(klass, alias) \ - static RegisterClassHelper g_Register ## klass(alias, DynamicObjectFactory) - -#define REGISTER_CLASS(klass) \ - REGISTER_CLASS_ALIAS(klass, #klass) - } #endif /* DYNAMICOBJECT_H */ diff --git a/lib/base/dynamictype.cpp b/lib/base/dynamictype.cpp new file mode 100644 index 000000000..9313a6d7a --- /dev/null +++ b/lib/base/dynamictype.cpp @@ -0,0 +1,118 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "i2-base.h" + +using namespace icinga; + +DynamicType::DynamicType(const String& name, const DynamicType::ObjectFactory& factory) + : m_Name(name), m_ObjectFactory(factory) +{ } + +DynamicType::Ptr DynamicType::GetByName(const String& name) +{ + DynamicType::TypeMap::const_iterator tt = GetTypes().find(name); + + if (tt == GetTypes().end()) + return DynamicType::Ptr(); + + return tt->second; +} + +DynamicType::TypeMap& DynamicType::GetTypes(void) +{ + static DynamicType::TypeMap types; + return types; +} + +DynamicType::NameMap& DynamicType::GetObjects(void) +{ + return m_Objects; +} + +String DynamicType::GetName(void) const +{ + return m_Name; +} + +void DynamicType::RegisterObject(const DynamicObject::Ptr& object) +{ + m_Objects[object->GetName()] = object; +} + +void DynamicType::UnregisterObject(const DynamicObject::Ptr& object) +{ + m_Objects.erase(object->GetName()); +} + +DynamicObject::Ptr DynamicType::GetObject(const String& name) const +{ + DynamicType::NameMap::const_iterator nt = m_Objects.find(name); + + if (nt == m_Objects.end()) + return DynamicObject::Ptr(); + + return nt->second; +} + +void DynamicType::RegisterType(const DynamicType::Ptr& type) +{ + if (GetByName(type->GetName())) + throw_exception(runtime_error("Cannot register class for type '" + + type->GetName() + "': Objects of this type already exist.")); + + GetTypes()[type->GetName()] = type; +} + +DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUpdate) const +{ + DynamicObject::Ptr obj = m_ObjectFactory(serializedUpdate); + + /* register attributes */ + String name; + DynamicAttributeType type; + BOOST_FOREACH(tuples::tie(name, type), m_Attributes) + obj->RegisterAttribute(name, type); + + /* apply the object's non-config attributes */ + obj->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config); + + return obj; +} + +bool DynamicType::TypeExists(const String& name) +{ + return (GetByName(name)); +} + +void DynamicType::AddAttribute(const String& name, DynamicAttributeType type) +{ + m_Attributes[name] = type; +} + +void DynamicType::RemoveAttribute(const String& name) +{ + m_Attributes.erase(name); +} + +void DynamicType::AddAttributes(const AttributeDescription *attributes, int attributeCount) +{ + for (int i = 0; i < attributeCount; i++) + AddAttribute(attributes[i].Name, attributes[i].Type); +} \ No newline at end of file diff --git a/lib/base/dynamictype.h b/lib/base/dynamictype.h new file mode 100644 index 000000000..7b47c75dc --- /dev/null +++ b/lib/base/dynamictype.h @@ -0,0 +1,110 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef DYNAMICTYPE_H +#define DYNAMICTYPE_H + +namespace icinga +{ + +struct AttributeDescription +{ + String Name; + DynamicAttributeType Type; +}; + +class I2_BASE_API DynamicType : public Object +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + typedef function ObjectFactory; + typedef map TypeMap; + typedef map NameMap; + + DynamicType(const String& name, const ObjectFactory& factory); + + String GetName(void) const; + + static DynamicType::Ptr GetByName(const String& name); + + static void RegisterType(const DynamicType::Ptr& type); + static bool TypeExists(const String& name); + + DynamicObject::Ptr CreateObject(const Dictionary::Ptr& serializedUpdate) const; + DynamicObject::Ptr GetObject(const String& name) const; + + void RegisterObject(const DynamicObject::Ptr& object); + void UnregisterObject(const DynamicObject::Ptr& object); + + static TypeMap& GetTypes(void); + NameMap& GetObjects(void); + + void AddAttribute(const String& name, DynamicAttributeType type); + void RemoveAttribute(const String& name); + + void AddAttributes(const AttributeDescription *attributes, int attributeCount); + +private: + String m_Name; + ObjectFactory m_ObjectFactory; + map m_Attributes; + + NameMap m_Objects; +}; + +/** + * Helper class for registering DynamicObject implementation classes. + * + * @ingroup base + */ +class RegisterTypeHelper +{ +public: + RegisterTypeHelper(const String& name, const DynamicType::ObjectFactory& factory, const AttributeDescription* attributes, int attributeCount) + { + if (!DynamicType::TypeExists(name)) { + DynamicType::Ptr type = boost::make_shared(name, factory); + type->AddAttributes(attributes, attributeCount); + DynamicType::RegisterType(type); + } + } +}; + +/** + * Factory function for DynamicObject-based classes. + * + * @ingroup base + */ +template +shared_ptr DynamicObjectFactory(const Dictionary::Ptr& serializedUpdate) +{ + return boost::make_shared(serializedUpdate); +} + +#define REGISTER_TYPE_ALIAS(type, alias, attributeDesc) \ + static RegisterTypeHelper g_Register ## type(alias, DynamicObjectFactory, attributeDesc, (attributeDesc == NULL) ? 0 : sizeof(attributeDesc) / sizeof((static_cast(attributeDesc))[0])) + +#define REGISTER_TYPE(type, attributeDesc) \ + REGISTER_TYPE_ALIAS(type, #type, attributeDesc) + +} + +#endif /* DYNAMICTYPE_H */ diff --git a/lib/base/i2-base.h b/lib/base/i2-base.h index c529d2850..0ec12ad5b 100644 --- a/lib/base/i2-base.h +++ b/lib/base/i2-base.h @@ -192,6 +192,7 @@ namespace tuples = boost::tuples; #include "scriptfunction.h" #include "scripttask.h" #include "dynamicobject.h" +#include "dynamictype.h" #include "logger.h" #include "application.h" #include "component.h" diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 3ed277df1..c9c9e7e13 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -21,7 +21,13 @@ using namespace icinga; -REGISTER_CLASS(Logger); +static AttributeDescription loggerAttributes[] = { + { "type", Attribute_Config }, + { "path", Attribute_Config }, + { "severity", Attribute_Config } +}; + +REGISTER_TYPE(Logger, loggerAttributes); /** * Constructor for the Logger class. @@ -31,10 +37,6 @@ REGISTER_CLASS(Logger); Logger::Logger(const Dictionary::Ptr& properties) : DynamicObject(properties) { - RegisterAttribute("type", Attribute_Config); - RegisterAttribute("path", Attribute_Config); - RegisterAttribute("severity", Attribute_Config); - if (!IsLocal()) throw_exception(runtime_error("Logger objects must be local.")); @@ -111,8 +113,10 @@ void Logger::ForwardLogEntry(const LogEntry& entry) { bool processed = false; + DynamicType::Ptr dt = DynamicType::GetByName("Logger"); + DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Logger")) { + BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) { Logger::Ptr logger = dynamic_pointer_cast(object); if (entry.Severity >= logger->GetMinSeverity()) diff --git a/lib/base/object.cpp b/lib/base/object.cpp index a0f7d03d2..5e7486b49 100644 --- a/lib/base/object.cpp +++ b/lib/base/object.cpp @@ -21,20 +21,14 @@ using namespace icinga; -boost::mutex Object::m_Mutex; -vector Object::m_HeldObjects; -#ifdef _DEBUG -set Object::m_AliveObjects; -#endif /* _DEBUG */ - /** * Default constructor for the Object class. */ Object::Object(void) { #ifdef _DEBUG - boost::mutex::scoped_lock lock(m_Mutex); - m_AliveObjects.insert(this); + boost::mutex::scoped_lock lock(GetMutex()); + GetAliveObjects().insert(this); #endif /* _DEBUG */ } @@ -44,8 +38,8 @@ Object::Object(void) Object::~Object(void) { #ifdef _DEBUG - boost::mutex::scoped_lock lock(m_Mutex); - m_AliveObjects.erase(this); + boost::mutex::scoped_lock lock(GetMutex()); + GetAliveObjects().erase(this); #endif /* _DEBUG */ } @@ -56,8 +50,8 @@ Object::~Object(void) */ void Object::Hold(void) { - boost::mutex::scoped_lock lock(m_Mutex); - m_HeldObjects.push_back(GetSelf()); + boost::mutex::scoped_lock lock(GetMutex()); + GetHeldObjects().push_back(GetSelf()); } /** @@ -65,8 +59,8 @@ void Object::Hold(void) */ void Object::ClearHeldObjects(void) { - boost::mutex::scoped_lock lock(m_Mutex); - m_HeldObjects.clear(); + boost::mutex::scoped_lock lock(GetMutex()); + GetHeldObjects().clear(); } /** @@ -85,10 +79,10 @@ Object::SharedPtrHolder Object::GetSelf(void) * * @returns The number of alive objects. */ -int Object::GetAliveObjects(void) +int Object::GetAliveObjectsCount(void) { - boost::mutex::scoped_lock lock(m_Mutex); - return m_AliveObjects.size(); + boost::mutex::scoped_lock lock(GetMutex()); + return GetAliveObjects().size(); } /** @@ -101,9 +95,9 @@ void Object::PrintMemoryProfile(void) ofstream dictfp("dictionaries.dump.tmp"); { - boost::mutex::scoped_lock lock(m_Mutex); + boost::mutex::scoped_lock lock(GetMutex()); set::iterator it; - BOOST_FOREACH(Object *obj, m_AliveObjects) { + BOOST_FOREACH(Object *obj, GetAliveObjects()) { pair::iterator, bool> tt; tt = types.insert(make_pair(Utility::GetTypeName(typeid(*obj)), 1)); if (!tt.second) @@ -130,4 +124,40 @@ void Object::PrintMemoryProfile(void) std::cerr << type << ": " << count << std::endl; } } + +/** + * Returns currently active objects. + * + * @returns currently active objects + */ +set& Object::GetAliveObjects(void) +{ + static set aliveObjects; + return aliveObjects; +} #endif /* _DEBUG */ + +/** + * Returns the mutex used for accessing static members. + * + * @returns a mutex + */ +boost::mutex& Object::GetMutex(void) +{ + static boost::mutex mutex; + return mutex; +} + +/** + * Returns currently held objects. The caller must be + * holding the mutex returned by GetMutex(). + * + * @returns currently held objects + */ +vector& Object::GetHeldObjects(void) +{ + static vector heldObjects; + return heldObjects; +} + + diff --git a/lib/base/object.h b/lib/base/object.h index 038819ac7..940f4837f 100644 --- a/lib/base/object.h +++ b/lib/base/object.h @@ -97,7 +97,7 @@ public: SharedPtrHolder GetSelf(void); #ifdef _DEBUG - static int GetAliveObjects(void); + static int GetAliveObjectsCount(void); static void PrintMemoryProfile(void); #endif /* _DEBUG */ @@ -109,14 +109,9 @@ private: Object(const Object& other); Object& operator=(const Object& rhs); - static boost::mutex m_Mutex; /**< Mutex which protects static members - of the Object class. */ - static vector m_HeldObjects; /**< Currently held - objects. */ -#ifdef _DEBUG - static set m_AliveObjects; /**< Currently alive objects - - for debugging purposes. */ -#endif /* _DEBUG */ + static boost::mutex& GetMutex(void); + static set& GetAliveObjects(void); + static vector& GetHeldObjects(void); }; /** diff --git a/lib/base/socket.cpp b/lib/base/socket.cpp index 3f5973eda..33f089182 100644 --- a/lib/base/socket.cpp +++ b/lib/base/socket.cpp @@ -37,6 +37,9 @@ Socket::Socket(void) */ Socket::~Socket(void) { + m_SendQueue->Close(); + m_RecvQueue->Close(); + Close(); } diff --git a/lib/base/tlsstream.cpp b/lib/base/tlsstream.cpp index 947ed9194..ae803a9f3 100644 --- a/lib/base/tlsstream.cpp +++ b/lib/base/tlsstream.cpp @@ -215,6 +215,9 @@ void TlsStream::Close(void) if (m_SSL) SSL_shutdown(m_SSL.get()); + m_SendQueue->Close(); + m_RecvQueue->Close(); + Stream::Close(); } diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 927ef341d..8690162f5 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -148,11 +148,13 @@ DynamicObject::Ptr ConfigItem::Commit(void) update->Set("attrs", attrs); update->Set("configTx", DynamicObject::GetCurrentTx()); + DynamicType::Ptr dtype = DynamicType::GetByName(GetType()); + if (!dobj) - dobj = DynamicObject::GetObject(GetType(), GetName()); + dobj = dtype->GetObject(GetName()); if (!dobj) - dobj = DynamicObject::Create(GetType(), update); + dobj = dtype->CreateObject(update); else dobj->ApplyUpdate(update, Attribute_Config); diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index b402780f0..7fafd7895 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -21,7 +21,12 @@ using namespace icinga; -REGISTER_CLASS(Host); +static AttributeDescription hostAttributes[] = { + { "alias", Attribute_Config }, + { "hostgroups", Attribute_Config } +}; + +REGISTER_TYPE(Host, hostAttributes); bool Host::m_InitializerDone = false; @@ -34,9 +39,6 @@ Host::Host(const Dictionary::Ptr& properties) m_InitializerDone = true; } - - RegisterAttribute("alias", Attribute_Config); - RegisterAttribute("hostgroups", Attribute_Config); } String Host::GetAlias(void) const diff --git a/lib/icinga/hostgroup.cpp b/lib/icinga/hostgroup.cpp index 1d9cc7b04..0838ef764 100644 --- a/lib/icinga/hostgroup.cpp +++ b/lib/icinga/hostgroup.cpp @@ -21,7 +21,13 @@ using namespace icinga; -REGISTER_CLASS(HostGroup); +static AttributeDescription hostGroupAttributes[] = { + { "alias", Attribute_Config }, + { "notes_url", Attribute_Config }, + { "action_url", Attribute_Config } +}; + +REGISTER_TYPE(HostGroup, hostGroupAttributes); String HostGroup::GetAlias(void) const { diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index a6500b4b9..68b716f47 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -21,13 +21,25 @@ #include #include "i2-icinga.h" +using namespace icinga; + +static AttributeDescription icingaApplicationAttributes[] = { + { "cert_path", Attribute_Config }, + { "ca_path", Attribute_Config }, + { "node", Attribute_Config }, + { "service", Attribute_Config }, + { "pid_path", Attribute_Config }, + { "state_path", Attribute_Config }, + { "macros", Attribute_Config } +}; + +REGISTER_TYPE(IcingaApplication, icingaApplicationAttributes); + #ifndef _WIN32 # include "icinga-version.h" # define ICINGA_VERSION GIT_MESSAGE #endif /* _WIN32 */ -using namespace icinga; - const String IcingaApplication::DefaultPidPath = "icinga2.pid"; const String IcingaApplication::DefaultStatePath = "icinga2.state"; diff --git a/lib/icinga/icingaapplication.h b/lib/icinga/icingaapplication.h index e238fa6ae..01c1a920b 100644 --- a/lib/icinga/icingaapplication.h +++ b/lib/icinga/icingaapplication.h @@ -64,8 +64,6 @@ private: void DumpProgramState(void); }; -REGISTER_CLASS(IcingaApplication); - } #endif /* ICINGAAPPLICATION_H */ diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index 4b1b24984..c01b7640e 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -21,7 +21,30 @@ using namespace icinga; -REGISTER_CLASS(Service); +static AttributeDescription serviceAttributes[] = { + { "alias", Attribute_Config }, + { "host_name", Attribute_Config }, + { "macros", Attribute_Config }, + { "check_command", Attribute_Config }, + { "max_check_attempts", Attribute_Config }, + { "check_interval", Attribute_Config }, + { "retry_interval", Attribute_Config }, + { "dependencies", Attribute_Config }, + { "servicegroups", Attribute_Config }, + { "checkers", Attribute_Config }, + + { "scheduling_offset", Attribute_Transient }, + { "next_check", Attribute_Replicated }, + { "checker", Attribute_Replicated }, + { "check_attempt", Attribute_Replicated }, + { "state", Attribute_Replicated }, + { "state_type", Attribute_Replicated }, + { "last_result", Attribute_Replicated }, + { "last_state_change", Attribute_Replicated }, + { "last_hard_state_change", Attribute_Replicated } +}; + +REGISTER_TYPE(Service, serviceAttributes); const int Service::DefaultMaxCheckAttempts = 3; const int Service::DefaultCheckInterval = 5 * 60; @@ -33,28 +56,7 @@ boost::signal Service::OnCheckerChang Service::Service(const Dictionary::Ptr& serializedObject) : DynamicObject(serializedObject) -{ - RegisterAttribute("alias", Attribute_Config); - RegisterAttribute("host_name", Attribute_Config); - RegisterAttribute("macros", Attribute_Config); - RegisterAttribute("check_command", Attribute_Config); - RegisterAttribute("max_check_attempts", Attribute_Config); - RegisterAttribute("check_interval", Attribute_Config); - RegisterAttribute("retry_interval", Attribute_Config); - RegisterAttribute("dependencies", Attribute_Config); - RegisterAttribute("servicegroups", Attribute_Config); - RegisterAttribute("checkers", Attribute_Config); - - RegisterAttribute("scheduling_offset", Attribute_Transient); - RegisterAttribute("next_check", Attribute_Replicated); - RegisterAttribute("checker", Attribute_Replicated); - RegisterAttribute("check_attempt", Attribute_Replicated); - RegisterAttribute("state", Attribute_Replicated); - RegisterAttribute("state_type", Attribute_Replicated); - RegisterAttribute("last_result", Attribute_Replicated); - RegisterAttribute("last_state_change", Attribute_Replicated); - RegisterAttribute("last_hard_state_change", Attribute_Replicated); -} +{ } String Service::GetAlias(void) const { diff --git a/lib/icinga/servicegroup.cpp b/lib/icinga/servicegroup.cpp index d5f5bc1b6..31b413fc4 100644 --- a/lib/icinga/servicegroup.cpp +++ b/lib/icinga/servicegroup.cpp @@ -21,7 +21,13 @@ using namespace icinga; -REGISTER_CLASS(ServiceGroup); +static AttributeDescription serviceGroupAttributes[] = { + { "alias", Attribute_Config }, + { "notes_url", Attribute_Config }, + { "action_url", Attribute_Config } +}; + +REGISTER_TYPE(ServiceGroup, serviceGroupAttributes); String ServiceGroup::GetAlias(void) const { diff --git a/lib/remoting/endpoint.cpp b/lib/remoting/endpoint.cpp index 1746189e7..99d26848e 100644 --- a/lib/remoting/endpoint.cpp +++ b/lib/remoting/endpoint.cpp @@ -21,7 +21,15 @@ using namespace icinga; -REGISTER_CLASS(Endpoint); +static AttributeDescription endpointAttributes[] = { + { "node", Attribute_Replicated }, + { "service", Attribute_Replicated }, + { "local", Attribute_Config }, + { "subscriptions", Attribute_Replicated }, + { "client", Attribute_Transient } +}; + +REGISTER_TYPE(Endpoint, endpointAttributes); boost::signal Endpoint::OnConnected; boost::signal Endpoint::OnDisconnected; @@ -35,13 +43,7 @@ boost::signal Endpoint::OnSubs */ Endpoint::Endpoint(const Dictionary::Ptr& serializedUpdate) : DynamicObject(serializedUpdate) -{ - RegisterAttribute("node", Attribute_Replicated); - RegisterAttribute("service", Attribute_Replicated); - RegisterAttribute("local", Attribute_Config); - RegisterAttribute("subscriptions", Attribute_Replicated); - RegisterAttribute("client", Attribute_Transient); -} +{ } /** * Checks whether an endpoint with the specified name exists. diff --git a/lib/remoting/endpointmanager.cpp b/lib/remoting/endpointmanager.cpp index c25801add..299e24ab5 100644 --- a/lib/remoting/endpointmanager.cpp +++ b/lib/remoting/endpointmanager.cpp @@ -151,6 +151,7 @@ void EndpointManager::NewClientHandler(const Socket::Ptr& client, TlsRole role) m_PendingClients.insert(tlsStream); tlsStream->OnConnected.connect(boost::bind(&EndpointManager::ClientConnectedHandler, this, _1, peerAddress)); + tlsStream->OnClosed.connect(boost::bind(&EndpointManager::ClientClosedHandler, this, _1)); client->Start(); } @@ -177,6 +178,12 @@ void EndpointManager::ClientConnectedHandler(const Stream::Ptr& client, const St endpoint->SetClient(jclient); } +void EndpointManager::ClientClosedHandler(const Stream::Ptr& client) +{ + TlsStream::Ptr tlsStream = static_pointer_cast(client); + m_PendingClients.erase(tlsStream); +} + /** * Sends a unicast message to the specified recipient. * @@ -213,7 +220,7 @@ void EndpointManager::SendAnycastMessage(const Endpoint::Ptr& sender, vector candidates; DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Endpoint")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) { Endpoint::Ptr endpoint = dynamic_pointer_cast(object); /* don't forward messages between non-local endpoints */ if (!sender->IsLocal() && !endpoint->IsLocal()) @@ -249,7 +256,7 @@ void EndpointManager::SendMulticastMessage(const Endpoint::Ptr& sender, throw_exception(invalid_argument("Message is missing the 'method' property.")); DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Endpoint")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) { Endpoint::Ptr recipient = dynamic_pointer_cast(object); /* don't forward messages back to the sender */ @@ -297,7 +304,7 @@ void EndpointManager::SubscriptionTimerHandler(void) Dictionary::Ptr subscriptions = boost::make_shared(); DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Endpoint")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) { Endpoint::Ptr endpoint = dynamic_pointer_cast(object); if (!endpoint->IsLocalEndpoint()) @@ -316,7 +323,7 @@ void EndpointManager::SubscriptionTimerHandler(void) void EndpointManager::ReconnectTimerHandler(void) { DynamicObject::Ptr object; - BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Endpoint")) { + BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) { Endpoint::Ptr endpoint = dynamic_pointer_cast(object); if (endpoint->IsConnected() || endpoint == m_Endpoint) diff --git a/lib/remoting/endpointmanager.h b/lib/remoting/endpointmanager.h index 9ae73ce43..b491846a1 100644 --- a/lib/remoting/endpointmanager.h +++ b/lib/remoting/endpointmanager.h @@ -103,6 +103,7 @@ private: void NewClientHandler(const Socket::Ptr& client, TlsRole rol); void ClientConnectedHandler(const Stream::Ptr& client, const String& peerAddress); + void ClientClosedHandler(const Stream::Ptr& client); }; } -- 2.40.0