]> granicus.if.org Git - icinga2/commitdiff
Implement support for tracking dependencies between config objects
authorGunnar Beutner <gunnar@beutner.name>
Tue, 25 Aug 2015 11:53:43 +0000 (13:53 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Tue, 25 Aug 2015 11:54:05 +0000 (13:54 +0200)
refs #9096

53 files changed:
lib/base/CMakeLists.txt
lib/base/application.cpp
lib/base/configobject.cpp
lib/base/configobject.hpp
lib/base/configobject.ti
lib/base/dependencygraph.cpp [new file with mode: 0644]
lib/base/dependencygraph.hpp [new file with mode: 0644]
lib/base/filelogger.cpp
lib/base/logger.cpp
lib/base/object.cpp
lib/base/object.hpp
lib/base/scriptutils.cpp
lib/base/scriptutils.hpp
lib/base/streamlogger.cpp
lib/base/type.cpp
lib/base/type.hpp
lib/checker/checkercomponent.cpp
lib/compat/compatlogger.cpp
lib/compat/externalcommandlistener.cpp
lib/compat/statusdatawriter.cpp
lib/db_ido/dbconnection.cpp
lib/demo/demo.cpp
lib/icinga/checkable.cpp
lib/icinga/dependency.cpp
lib/icinga/dependency.ti
lib/icinga/host.cpp
lib/icinga/host.ti
lib/icinga/hostgroup.ti
lib/icinga/icingastatuswriter.cpp
lib/icinga/notification.cpp
lib/icinga/notification.ti
lib/icinga/scheduleddowntime.cpp
lib/icinga/scheduleddowntime.ti
lib/icinga/service.cpp
lib/icinga/service.ti
lib/icinga/servicegroup.ti
lib/icinga/timeperiod.cpp
lib/icinga/user.cpp
lib/icinga/user.ti
lib/icinga/usergroup.ti
lib/livestatus/livestatuslistener.cpp
lib/notification/notificationcomponent.cpp
lib/perfdata/gelfwriter.cpp
lib/perfdata/graphitewriter.cpp
lib/perfdata/opentsdbwriter.cpp
lib/perfdata/perfdatawriter.cpp
lib/remote/apilistener.cpp
lib/remote/statusqueryhandler.cpp
lib/remote/zone.ti
tools/mkclass/class_lexer.ll
tools/mkclass/class_parser.yy
tools/mkclass/classcompiler.cpp
tools/mkclass/classcompiler.hpp

index 853068f47e48c2da98ce0c6c1ecd84dfc2fff4f7..2754ea39a472e1b56b94376a014ba0cbf67c2c06 100644 (file)
@@ -26,7 +26,7 @@ set(base_SOURCES
   application.cpp application.thpp application-version.cpp array.cpp
   array-script.cpp boolean.cpp boolean-script.cpp console.cpp context.cpp
   convert.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp
-  configobject.cpp configobject.thpp configobject-script.cpp configtype.cpp
+  configobject.cpp configobject.thpp configobject-script.cpp configtype.cpp dependencygraph.cpp
   exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp
   json-script.cpp loader.cpp logger.cpp logger.thpp math-script.cpp
   netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp
index a11e722a7c77e3932a10bde8e2aba818d3483077..1363410b0bba3a9745498273d09f789f92e6e4c8 100644 (file)
@@ -102,7 +102,7 @@ void Application::Stop(void)
        } else
                ClosePidFile(true);
 
-       ConfigObject::Stop();
+       ObjectImpl<Application>::Stop();
 }
 
 Application::~Application(void)
index 8ac18d65c54f9387c930402478fa269c315d8715..1d895676c06692d271daa7bbe731f3875b27d5d5 100644 (file)
@@ -231,6 +231,8 @@ void ConfigObject::Unregister(void)
 
 void ConfigObject::Start(void)
 {
+       ObjectImpl<ConfigObject>::Start();
+
        ASSERT(!OwnsLock());
        ObjectLock olock(this);
 
@@ -260,6 +262,8 @@ void ConfigObject::Activate(void)
 
 void ConfigObject::Stop(void)
 {
+       ObjectImpl<ConfigObject>::Stop();
+
        ASSERT(!OwnsLock());
        ObjectLock olock(this);
 
@@ -501,5 +505,7 @@ void ConfigObject::DumpModifiedAttributes(const boost::function<void(const Confi
 ConfigObject::Ptr ConfigObject::GetObject(const String& type, const String& name)
 {
        ConfigType::Ptr dtype = ConfigType::GetByName(type);
+       if (!dtype)
+               return ConfigObject::Ptr();
        return dtype->GetObject(name);
 }
index 5885621f2add2cd28560ed5d4183ee9c72aa167b..fae5e0520ed9fa1c454ba15a46e75c8cbaacaddf 100644 (file)
@@ -64,8 +64,8 @@ public:
        void Deactivate(void);
        void SetAuthority(bool authority);
 
-       virtual void Start(void);
-       virtual void Stop(void);
+       virtual void Start(void) override;
+       virtual void Stop(void) override;
 
        virtual void Pause(void);
        virtual void Resume(void);
@@ -83,6 +83,8 @@ public:
                return static_pointer_cast<T>(object);
        }
 
+       static ConfigObject::Ptr GetObject(const String& type, const String& name);
+
        static void DumpObjects(const String& filename, int attributeTypes = FAState);
        static void RestoreObjects(const String& filename, int attributeTypes = FAState);
        static void StopObjects(void);
@@ -95,7 +97,6 @@ protected:
        explicit ConfigObject(void);
 
 private:
-       static ConfigObject::Ptr GetObject(const String& type, const String& name);
        static void RestoreObject(const String& message, int attributeTypes);
 };
 
index 3aa6cc79c9d05097b2267b0e73d12851813a6f5a..e3c6f857eec6f23d0eff5690bfc76fbfc1789dd6 100644 (file)
@@ -55,6 +55,12 @@ public:
                m_DebugInfo = di;
        }
 
+       inline virtual void Start(void)
+       { }
+
+       inline virtual void Stop(void)
+       { }
+
 private:
        DebugInfo m_DebugInfo;
 };
diff --git a/lib/base/dependencygraph.cpp b/lib/base/dependencygraph.cpp
new file mode 100644 (file)
index 0000000..5bb9d65
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2015 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 "base/dependencygraph.hpp"
+#include <boost/foreach.hpp>
+
+using namespace icinga;
+
+boost::mutex DependencyGraph::m_Mutex;
+std::map<Object *, std::map<Object *, int> > DependencyGraph::m_Dependencies;
+
+void DependencyGraph::AddDependency(Object *parent, Object *child)
+{
+       boost::mutex::scoped_lock lock(m_Mutex);
+       m_Dependencies[child][parent]++;
+}
+
+void DependencyGraph::RemoveDependency(Object *parent, Object *child)
+{
+       boost::mutex::scoped_lock lock(m_Mutex);
+       m_Dependencies[child][parent]--;
+}
+
+std::vector<Object::Ptr> DependencyGraph::GetParents(const Object::Ptr& child)
+{
+       std::vector<Object::Ptr> objects;
+
+       boost::mutex::scoped_lock lock(m_Mutex);
+       std::map<Object *, std::map<Object *, int> >::const_iterator it = m_Dependencies.find(child.get());
+
+       if (it != m_Dependencies.end()) {
+               typedef std::pair<Object *, int> kv_pair;
+               BOOST_FOREACH(const kv_pair& kv, it->second) {
+                       objects.push_back(kv.first);
+               }
+       }
+
+       return objects;
+}
diff --git a/lib/base/dependencygraph.hpp b/lib/base/dependencygraph.hpp
new file mode 100644 (file)
index 0000000..6b4e4bc
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2015 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 DEPENDENCYGRAPH_H
+#define DEPENDENCYGRAPH_H
+
+#include "base/i2-base.hpp"
+#include "base/object.hpp"
+#include <map>
+
+namespace icinga {
+
+/**
+ * A graph that tracks dependencies between objects.
+ *
+ * @ingroup base
+ */
+class I2_BASE_API DependencyGraph
+{
+public:
+       static void AddDependency(Object *parent, Object *child);
+       static void RemoveDependency(Object *parent, Object *child);
+       static std::vector<Object::Ptr> GetParents(const Object::Ptr& child);
+
+private:
+       DependencyGraph(void);
+
+       static boost::mutex m_Mutex;
+       static std::map<Object *, std::map<Object *, int> > m_Dependencies;
+};
+
+}
+
+#endif /* DEPENDENCYGRAPH_H */
index 4a80f131e3eca2dd2ff08e650c6723fed0cc6de4..afd4c606b941430736860f6a056392c67d076896 100644 (file)
@@ -46,7 +46,7 @@ void FileLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
  */
 void FileLogger::Start(void)
 {
-       StreamLogger::Start();
+       ObjectImpl<FileLogger>::Start();
 
        ReopenLogFile();
 
index 27151a9cf6051d326a87f3a822f817714123d9c3..c7cf16169a892d75f6ffc373fa177a9d4f673681 100644 (file)
@@ -54,7 +54,7 @@ void Logger::StaticInitialize(void)
  */
 void Logger::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<Logger>::Start();
 
        boost::mutex::scoped_lock lock(m_Mutex);
        m_Loggers.insert(this);
@@ -67,7 +67,7 @@ void Logger::Stop(void)
                m_Loggers.erase(this);
        }
 
-       ConfigObject::Stop();
+       ObjectImpl<Logger>::Stop();
 }
 
 std::set<Logger::Ptr> Logger::GetLoggers(void)
index ed7cd9efc2837c470d0f4b0825844144e8e0e8bf..38fd82fd461342a92c8190092189fc76ddd0f276 100644 (file)
@@ -92,6 +92,11 @@ Value Object::GetField(int id) const
                BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID."));
 }
 
+void Object::Validate(int types, const ValidationUtils& utils)
+{
+       /* Nothing to do here. */
+}
+
 void Object::ValidateField(int id, const Value& value, const ValidationUtils& utils)
 {
        /* Nothing to do here. */
index e6b0875d005b8dbe4c2ab4865fe38093dfba854e..b56377bf52dfefbeb62737beffab39d237686f53 100644 (file)
@@ -103,6 +103,8 @@ public:
 
        virtual intrusive_ptr<Type> GetReflectionType(void) const;
 
+       virtual void Validate(int types, const ValidationUtils& utils);
+
        virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty);
        virtual Value GetField(int id) const;
        virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils);
index c43525176de7a662531db3bfd186bb8289e4a1ab..085c7260ca44af0410d0679500a052ecad87b7bd 100644 (file)
@@ -26,6 +26,7 @@
 #include "base/objectlock.hpp"
 #include "base/configtype.hpp"
 #include "base/application.hpp"
+#include "base/dependencygraph.hpp"
 #include <boost/foreach.hpp>
 #include <boost/regex.hpp>
 #include <algorithm>
@@ -57,6 +58,7 @@ REGISTER_SAFE_SCRIPTFUNCTION(get_time, &Utility::GetTime);
 REGISTER_SAFE_SCRIPTFUNCTION(basename, &Utility::BaseName);
 REGISTER_SAFE_SCRIPTFUNCTION(dirname, &Utility::DirName);
 REGISTER_SAFE_SCRIPTFUNCTION(msi_get_component_path, &ScriptUtils::MsiGetComponentPathShim);
+REGISTER_SAFE_SCRIPTFUNCTION(track_parents, &ScriptUtils::TrackParents);
 
 String ScriptUtils::CastString(const Value& value)
 {
@@ -304,3 +306,9 @@ String ScriptUtils::MsiGetComponentPathShim(const String& component)
        return String();
 #endif /* _WIN32 */
 }
+
+Array::Ptr ScriptUtils::TrackParents(const Object::Ptr& child)
+{
+       return Array::FromVector(DependencyGraph::GetParents(child));
+}
+
index 204ca7761d1251fcc45b95dcc56a6b8d584961c7..c4a0d477ff9c984b325dc5e64607d45570896618 100644 (file)
@@ -51,6 +51,7 @@ public:
        static Array::Ptr GetObjects(const Type::Ptr& type);
        static void Assert(const Value& arg);
        static String MsiGetComponentPathShim(const String& component);
+       static Array::Ptr TrackParents(const Object::Ptr& parent);
 
 private:
        ScriptUtils(void);
index 63ac98f6a28663c674443dbd34b1305ffea32b45..0791a2ad43921eaa3331ab252a0dc01f9a651ed6 100644 (file)
@@ -39,7 +39,7 @@ StreamLogger::StreamLogger(void)
 
 void StreamLogger::Stop(void)
 {
-       Logger::Stop();
+       ObjectImpl<StreamLogger>::Stop();
 
        // make sure we flush the log data on shutdown, even if we don't call the destructor
        if (m_Stream)
index 52300ebf45096a904a91222bf98c7d2119258864..4d61da62b44df9d06cee2ddbab345436a9dbae88 100644 (file)
@@ -159,9 +159,9 @@ int TypeType::GetFieldId(const String& name) const
 Field TypeType::GetFieldInfo(int id) const
 {
        if (id == 0)
-               return Field(0, "Object", "prototype", NULL, 0);
+               return Field(0, "Object", "prototype", NULL, 0, 0);
        else if (id == 1)
-               return Field(1, "Object", "base", NULL, 0);
+               return Field(1, "Object", "base", NULL, 0, 0);
 
        throw std::runtime_error("Invalid field ID.");
 }
index 6417a5c84c8cdc596433d33675918faf20de8174..4084e8b998e0820340910cf5b21a285d954191f1 100644 (file)
@@ -49,9 +49,10 @@ struct Field
        const char *Name;
        const char *RefTypeName;
        int Attributes;
+       int ArrayRank;
 
-       Field(int id, const char *type, const char *name, const char *reftype, int attributes)
-               : ID(id), TypeName(type), Name(name), RefTypeName(reftype), Attributes(attributes)
+       Field(int id, const char *type, const char *name, const char *reftype, int attributes, int arrayRank)
+               : ID(id), TypeName(type), Name(name), RefTypeName(reftype), Attributes(attributes), ArrayRank(arrayRank)
        { }
 };
 
index 1759813843123c8e9998bbd200323b65a40444a5..fa7bf978af95cb6db29cc23900ad463948c67c5a 100644 (file)
@@ -74,7 +74,7 @@ void CheckerComponent::OnConfigLoaded(void)
 
 void CheckerComponent::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<CheckerComponent>::Start();
 
        m_Thread = boost::thread(boost::bind(&CheckerComponent::CheckThreadProc, this));
 
@@ -97,7 +97,7 @@ void CheckerComponent::Stop(void)
        m_ResultTimer->Stop();
        m_Thread.join();
 
-       ConfigObject::Stop();
+       ObjectImpl<CheckerComponent>::Stop();
 }
 
 void CheckerComponent::CheckThreadProc(void)
index ff0f38ba6814256449ecad3f4fc89eb213da67e6..3f0b679476bb06d70990fb41c885041abe3a65a6 100644 (file)
@@ -59,7 +59,7 @@ void CompatLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
  */
 void CompatLogger::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<CompatLogger>::Start();
 
        Checkable::OnNewCheckResult.connect(bind(&CompatLogger::CheckResultHandler, this, _1, _2));
        Checkable::OnNotificationSentToUser.connect(bind(&CompatLogger::NotificationSentHandler, this, _1, _2, _3, _4, _5, _6, _7, _8));
index c13696738f3a61d65d30eecb6d4cf8c6837e7a6d..ec5beca15ecc7a1dd5524cb66719d4e75857b0e7 100644 (file)
@@ -48,7 +48,7 @@ void ExternalCommandListener::StatsFunc(const Dictionary::Ptr& status, const Arr
  */
 void ExternalCommandListener::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<ExternalCommandListener>::Start();
 
 #ifndef _WIN32
        m_CommandThread = boost::thread(boost::bind(&ExternalCommandListener::CommandPipeThread, this, GetCommandPath()));
index 20f0804726deaeb06b3edfa75351e5d650e2b564..97f2528d7579c5a301c0f367b4e429333423744c 100644 (file)
@@ -72,7 +72,7 @@ void StatusDataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr
  */
 void StatusDataWriter::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<StatusDataWriter>::Start();
 
        m_StatusTimer = new Timer();
        m_StatusTimer->SetInterval(GetUpdateInterval());
index 9c239eefbe4b4942d67d8c447e0e11fe1a3d549c..986995b1852f29a198873ff8de38014b12ffbecb 100644 (file)
@@ -58,7 +58,7 @@ void DbConnection::OnConfigLoaded(void)
 
 void DbConnection::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<DbConnection>::Start();
 
        DbObject::OnQuery.connect(boost::bind(&DbConnection::ExecuteQuery, this, _1));
        ConfigObject::OnActiveChanged.connect(boost::bind(&DbConnection::UpdateObject, this, _1));
index 221a138b4f454db37eaaa2abb52de8442a2edb20..6ecd8008b1ecf8d63df47bac609571505d18d82c 100644 (file)
@@ -35,7 +35,7 @@ REGISTER_APIFUNCTION(HelloWorld, demo, &Demo::DemoMessageHandler);
  */
 void Demo::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<Demo>::Start();
 
        m_DemoTimer = new Timer();
        m_DemoTimer->SetInterval(5);
index bccb68fed7e6efe47f2cec1174d0488728ff318e..76f5863075e9ad6e22d7bad1b52148b9dc808507 100644 (file)
@@ -47,7 +47,7 @@ void Checkable::Start(void)
        if (GetNextCheck() < now + 300)
                UpdateNextCheck();
 
-       ConfigObject::Start();
+       ObjectImpl<Checkable>::Start();
 }
 
 void Checkable::OnStateLoaded(void)
index de7ebf390daead15c8ca0f42eff49a8d9bb2614f..b4d364011b01f21890a6561f03764afe21b652db 100644 (file)
@@ -82,7 +82,7 @@ void Dependency::OnConfigLoaded(void)
 
 void Dependency::OnAllConfigLoaded(void)
 {
-       ConfigObject::OnAllConfigLoaded();
+       ObjectImpl<Dependency>::OnAllConfigLoaded();
 
        Host::Ptr childHost = Host::GetByName(GetChildHostName());
 
@@ -125,7 +125,7 @@ void Dependency::OnAllConfigLoaded(void)
 
 void Dependency::Stop(void)
 {
-       ConfigObject::Stop();
+       ObjectImpl<Dependency>::Stop();
 
        GetChild()->RemoveDependency(this);
        GetParent()->RemoveReverseDependency(this);
@@ -232,3 +232,4 @@ void Dependency::ValidateStates(const Array::Ptr& value, const ValidationUtils&
        if (!GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0)
                BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid for service dependency."));
 }
+
index 2d70896636552ab284ff7cb309806c94b287b7e6..a158530424a95b9e766c4c93b24e8996480555e7 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "icinga/customvarobject.hpp"
 #include "icinga/checkable.hpp"
+#impl_include "icinga/service.hpp"
 
 library icinga;
 
@@ -40,14 +41,38 @@ class Dependency : CustomVarObject < DependencyNameComposer
        load_after Service;
 
        [config, required] name(Host) child_host_name;
-       [config] String child_service_name;
+       [config] String child_service_name {
+               track {{{
+                       if (!oldValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetParentHostName(), oldValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+
+                       if (!newValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetParentHostName(), newValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+               }}}
+       };
 
        [config, required] name(Host) parent_host_name;
-       [config] String parent_service_name;
+       [config] String parent_service_name {
+               track {{{
+                       if (!oldValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetParentHostName(), oldValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+
+                       if (!newValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetParentHostName(), newValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+               }}}
+       };
 
        [config] name(TimePeriod) period (PeriodRaw);
 
-       [config] Array::Ptr states;
+       [config] array(double) states;
        int state_filter_real (StateFilter);
 
        [config] bool ignore_soft_states {
@@ -60,10 +85,4 @@ class Dependency : CustomVarObject < DependencyNameComposer
        };
 };
 
-validator Dependency {
-       Array states {
-               Number "*";
-       };
-};
-
 }
index db05304714a369d26f46b91e72b48ae646a4e6a0..955bba397fad42578a2b04b83bb0096b56caf7dd 100644 (file)
@@ -36,7 +36,7 @@ REGISTER_TYPE(Host);
 
 void Host::OnAllConfigLoaded(void)
 {
-       Checkable::OnAllConfigLoaded();
+       ObjectImpl<Host>::OnAllConfigLoaded();
 
        HostGroup::EvaluateObjectRules(this);
 
@@ -73,7 +73,7 @@ void Host::CreateChildObjects(const Type::Ptr& childType)
 
 void Host::Stop(void)
 {
-       Checkable::Stop();
+       ObjectImpl<Host>::Stop();
 
        Array::Ptr groups = GetGroups();
 
index c8cf945b3b1f263e247401409ff82661a5c03f0e..06c96dcc119759b6aeaee9e2e8a6e10ba2a536ad 100644 (file)
@@ -27,7 +27,7 @@ namespace icinga
 
 class Host : Checkable
 {
-       [config] Array::Ptr groups {
+       [config] array(name(HostGroup)) groups {
                default {{{ return new Array(); }}}
        };
 
@@ -55,10 +55,4 @@ class Host : Checkable
 
 };
 
-validator Host {
-       Array groups {
-               name(HostGroup) "*";
-       };
-};
-
 }
index 514167a9083c2e92ba9a0be38cbf91e89cb9a6e3..2b8d4175ce76a80ed08e34422aac432261fd8c05 100644 (file)
@@ -35,16 +35,10 @@ class HostGroup : CustomVarObject
                }}}
        };
 
-       [config] Array::Ptr groups;
+       [config] array(name(HostGroup)) groups;
        [config] String notes;
        [config] String notes_url;
        [config] String action_url;
 };
 
-validator HostGroup {
-       Array groups {
-               name(HostGroup) "*";
-       };
-};
-
 }
index b9963783c4f05d847a7714c5055ef23b94091756..44e8f3c8c7a374ab55263b44a29f20552c5c208b 100644 (file)
@@ -58,7 +58,7 @@ void IcingaStatusWriter::StatsFunc(const Dictionary::Ptr& status, const Array::P
  */
 void IcingaStatusWriter::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<IcingaStatusWriter>::Start();
 
        m_StatusTimer = new Timer();
        m_StatusTimer->SetInterval(GetUpdateInterval());
index 5488345c52930188247afbef4f273fa6ea45b88f..5c25ffbbece5f7c2ad7bc605f9ef37cfec0c0d52 100644 (file)
@@ -115,7 +115,7 @@ void Notification::OnAllConfigLoaded(void)
 
 void Notification::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<Notification>::Start();
 
        Checkable::Ptr obj = GetCheckable();
 
@@ -125,7 +125,7 @@ void Notification::Start(void)
 
 void Notification::Stop(void)
 {
-       ConfigObject::Stop();
+       ObjectImpl<Notification>::Stop();
 
        Checkable::Ptr obj = GetCheckable();
 
@@ -676,3 +676,4 @@ Endpoint::Ptr Notification::GetCommandEndpoint(void) const
 {
        return Endpoint::GetByName(GetCommandEndpointRaw());
 }
+
index 28c8b4b701216c601ff40999e9ce726d34828f44..dc83ce7b162c926459d155bbfa068e0ad7d296e7 100644 (file)
@@ -18,6 +18,7 @@
  ******************************************************************************/
 
 #include "icinga/customvarobject.hpp"
+#impl_include "icinga/service.hpp"
 
 library icinga;
 
@@ -43,15 +44,27 @@ class Notification : CustomVarObject < NotificationNameComposer
                default {{{ return 1800; }}}
        };
        [config] name(TimePeriod) period (PeriodRaw);
-       [config, protected] Array::Ptr users (UsersRaw);
-       [config, protected] Array::Ptr user_groups (UserGroupsRaw);
+       [config, protected] array(name(User)) users (UsersRaw);
+       [config, protected] array(name(UserGroup)) user_groups (UserGroupsRaw);
        [config] Dictionary::Ptr times;
-       [config] Array::Ptr types;
+       [config] array(double) types;
        int type_filter_real (TypeFilter);
-       [config] Array::Ptr states;
+       [config] array(double) states;
        int state_filter_real (StateFilter);
        [config, protected, required] name(Host) host_name;
-       [config, protected] String service_name;
+       [config, protected] String service_name {
+               track {{{
+                       if (!oldValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+
+                       if (!newValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetHostName(), newValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+               }}}
+       };
 
        [state] Array::Ptr notified_users {
                default {{{ return new Array(); }}}
@@ -66,26 +79,10 @@ class Notification : CustomVarObject < NotificationNameComposer
 };
 
 validator Notification {
-       Array users {
-               name(User) "*";
-       };
-
-       Array user_groups {
-               name(UserGroup) "*";
-       };
-
        Dictionary times {
                Number begin;
                Number end;
        };
-
-       Array types {
-               Number "*";
-       };
-
-       Array states {
-               Number "*";
-       };
 };
 
 }
index 908493fb0b36c6301f97bc1f4f4fe1a4cb5222b0..763e9fa7e33ffba3028d84af038f62fc20a14074 100644 (file)
@@ -90,7 +90,7 @@ void ScheduledDowntime::StaticInitialize(void)
 
 void ScheduledDowntime::OnAllConfigLoaded(void)
 {
-       CustomVarObject::OnAllConfigLoaded();
+       ObjectImpl<ScheduledDowntime>::OnAllConfigLoaded();
 
        if (!GetCheckable())
                BOOST_THROW_EXCEPTION(ScriptError("ScheduledDowntime '" + GetName() + "' references a host/service which doesn't exist.", GetDebugInfo()));
@@ -98,7 +98,7 @@ void ScheduledDowntime::OnAllConfigLoaded(void)
 
 void ScheduledDowntime::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<ScheduledDowntime>::Start();
 
        CreateNextDowntime();
 }
@@ -231,3 +231,4 @@ void ScheduledDowntime::ValidateRanges(const Dictionary::Ptr& value, const Valid
                }
        }
 }
+
index c41363aebd4e9e1d2f6dc9ba753e3aaac6452d21..dedefc3dc7436f1c1a0531fdbaaea7d29aa5e3a7 100644 (file)
@@ -18,6 +18,7 @@
  ******************************************************************************/
 
 #include "icinga/customvarobject.hpp"
+#impl_include "icinga/service.hpp"
 
 library icinga;
 
@@ -39,7 +40,19 @@ class ScheduledDowntime : CustomVarObject < ScheduledDowntimeNameComposer
        load_after Service;
 
        [config, protected, required] name(Host) host_name;
-       [config, protected] String service_name;
+       [config, protected] String service_name {
+               track {{{
+                       if (!oldValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+
+                       if (!newValue.IsEmpty()) {
+                               Service::Ptr service = Service::GetByNamePair(GetHostName(), newValue);
+                               DependencyGraph::RemoveDependency(this, service.get());
+                       }
+               }}}
+       };
 
        [config, required] String author;
        [config, required] String comment;
index aa713a6c01a58aceb7d0966edb98076d0b705fd9..35a83e9719326933039547739ad2be02c368e631 100644 (file)
@@ -61,7 +61,7 @@ Dictionary::Ptr ServiceNameComposer::ParseName(const String& name) const
 
 void Service::OnAllConfigLoaded(void)
 {
-       Checkable::OnAllConfigLoaded();
+       ObjectImpl<Service>::OnAllConfigLoaded();
 
        m_Host = Host::GetByName(GetHostName());
 
index 49e96bf55308f97242eef1f0557de87c1c24f17c..d3f939bdc4d00e78b03a5454eb1086ccc4c2883b 100644 (file)
@@ -40,7 +40,7 @@ class Service : Checkable < ServiceNameComposer
 {
        load_after Host;
 
-       [config] Array::Ptr groups {
+       [config] array(name(ServiceGroup)) groups {
                default {{{ return new Array(); }}}
        };
 
@@ -70,10 +70,4 @@ class Service : Checkable < ServiceNameComposer
        };
 };
 
-validator Service {
-       Array groups {
-               name(ServiceGroup) "*";
-       };
-};
-
 }
index fb37b69e49c9e2136095344824ce6d8ef2b5dc89..eb69b56dc5e3fe7d17e234bd7f67d3309ef2e5a6 100644 (file)
@@ -35,16 +35,10 @@ class ServiceGroup : CustomVarObject
                }}}
        };
 
-       [config] Array::Ptr groups;
+       [config] array(name(ServiceGroup)) groups;
        [config] String notes;
        [config] String notes_url;
        [config] String action_url;
 };
 
-validator ServiceGroup {
-       Array groups {
-               name(ServiceGroup) "*";
-       };
-};
-
 }
index 7a37ee80af2f6ff4965cc14611fdb7e3ce52addf..651a0d3f4438e071542e56e6c92bd4668a6648c5 100644 (file)
@@ -46,7 +46,7 @@ void TimePeriod::StaticInitialize(void)
 
 void TimePeriod::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<TimePeriod>::Start();
 
        /* Pre-fill the time period for the next 24 hours. */
        double now = Utility::GetTime();
index ff4d9661fd8f503eaac34044a45c3099f54d087b..f8f1704952e04189fce1b964c9dc9342c3503a83 100644 (file)
@@ -32,7 +32,7 @@ REGISTER_TYPE(User);
 
 void User::OnConfigLoaded(void)
 {
-       ConfigObject::OnConfigLoaded();
+       ObjectImpl<User>::OnConfigLoaded();
 
        SetTypeFilter(FilterArrayToInt(GetTypes(), ~0));
        SetStateFilter(FilterArrayToInt(GetStates(), ~0));
@@ -40,7 +40,7 @@ void User::OnConfigLoaded(void)
 
 void User::OnAllConfigLoaded(void)
 {
-       ConfigObject::OnAllConfigLoaded();
+       ObjectImpl<User>::OnAllConfigLoaded();
 
        UserGroup::EvaluateObjectRules(this);
 
@@ -62,7 +62,7 @@ void User::OnAllConfigLoaded(void)
 
 void User::Stop(void)
 {
-       ConfigObject::Stop();
+       ObjectImpl<User>::Stop();
 
        Array::Ptr groups = GetGroups();
 
index 5c7a9ed8003b976d73c4eb5ddf7fa42b3961f75d..a3940e323a27bfff14e44f771aaee264e0140317 100644 (file)
@@ -35,13 +35,13 @@ class User : CustomVarObject
                                return m_DisplayName;
                }}}
        };
-       [config] Array::Ptr groups {
+       [config] array(name(UserGroup)) groups {
                default {{{ return new Array(); }}}
        };
        [config] name(TimePeriod) period (PeriodRaw);
-       [config] Array::Ptr types;
+       [config] array(double) types;
        int type_filter_real (TypeFilter);
-       [config] Array::Ptr states;
+       [config] array(double) states;
        int state_filter_real (StateFilter);
 
        [config] String email;
@@ -54,18 +54,4 @@ class User : CustomVarObject
        [state] double last_notification;
 };
 
-validator User {
-       Array groups {
-               name(UserGroup) "*";
-       };
-
-       Array types {
-               Number "*";
-       };
-
-       Array states {
-               Number "*";
-       };
-};
-
 }
index 11cda143be109a68fad0bb30269ed545ba526873..f1c480a41c090510a06b17b8e39d2f9187ab3d95 100644 (file)
@@ -35,13 +35,7 @@ class UserGroup : CustomVarObject
                }}}
        };
 
-       [config] Array::Ptr groups;
-};
-
-validator UserGroup {
-       Array groups {
-               name(UserGroup) "*";
-       };
+       [config] array(name(UserGroup)) groups;
 };
 
 }
index 98aa99db6a4a49ac147eb7fb46ef48403e8d41a7..da55f6f9025f4fa0b29de8302cf998a6f61526ff 100644 (file)
@@ -64,7 +64,7 @@ void LivestatusListener::StatsFunc(const Dictionary::Ptr& status, const Array::P
  */
 void LivestatusListener::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<LivestatusListener>::Start();
 
        if (GetSocketType() == "tcp") {
                TcpSocket::Ptr socket = new TcpSocket();
@@ -121,7 +121,7 @@ void LivestatusListener::Start(void)
 
 void LivestatusListener::Stop(void)
 {
-       ConfigObject::Stop();
+       ObjectImpl<LivestatusListener>::Stop();
 
        m_Listener->Close();
 
index ccd2f61549a71e46c82e0a246ad1e2de31767ea5..b85e8ecd4d8497449141ef8a0931c97e1244d878 100644 (file)
@@ -51,7 +51,7 @@ void NotificationComponent::StatsFunc(const Dictionary::Ptr& status, const Array
  */
 void NotificationComponent::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<NotificationComponent>::Start();
 
        Checkable::OnNotificationsRequested.connect(boost::bind(&NotificationComponent::SendNotificationsHandler, this, _1,
            _2, _3, _4, _5));
index 10a9a948f997cca2d97e55fef86ef4aa692ae891..053a8f8dd92ab061961933dd764836233866718b 100644 (file)
@@ -40,7 +40,7 @@ REGISTER_TYPE(GelfWriter);
 
 void GelfWriter::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<GelfWriter>::Start();
 
        m_ReconnectTimer = new Timer();
        m_ReconnectTimer->SetInterval(10);
index 8a48ceb6650183536bc9f8d0187a9c4851aaed19..dd36104e733579fcaa0acf9118db2504856d46a8 100644 (file)
@@ -60,7 +60,7 @@ void GraphiteWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
 
 void GraphiteWriter::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<GraphiteWriter>::Start();
 
        m_ReconnectTimer = new Timer();
        m_ReconnectTimer->SetInterval(10);
index b8c51414baff1da69feaff0968fc6027d2a6124e..8fa0f71312eaa840343bb2a315be5da44ed21fb0 100644 (file)
@@ -60,7 +60,7 @@ void OpenTsdbWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
 
 void OpenTsdbWriter::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<OpenTsdbWriter>::Start();
 
        m_ReconnectTimer = new Timer();
        m_ReconnectTimer->SetInterval(10);
index 0f9cc664c55baee652c20563083deef15690aea0..44e000d0296f52781d1902528d24b1c3f411ae04 100644 (file)
@@ -51,7 +51,7 @@ void PerfdataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
 
 void PerfdataWriter::Start(void)
 {
-       ConfigObject::Start();
+       ObjectImpl<PerfdataWriter>::Start();
 
        Checkable::OnNewCheckResult.connect(boost::bind(&PerfdataWriter::CheckResultHandler, this, _1, _2));
 
index f743daf48e307da161622ca7af8adfc0802ad318..3c27a38c5aafb8e10d1de293a6ccfb35332c0042 100644 (file)
@@ -102,7 +102,7 @@ void ApiListener::Start(void)
                return;
        }
 
-       ConfigObject::Start();
+       ObjectImpl<ApiListener>::Start();
 
        {
                boost::mutex::scoped_lock(m_LogLock);
index 153c86ddf9096a1a14cb5f5fff45a71d11061ef3..71df3a21a474ef68f21398f225b8dc1ae31bfa28 100644 (file)
@@ -21,6 +21,8 @@
 #include "remote/httputility.hpp"
 #include "remote/filterutility.hpp"
 #include "base/serializer.hpp"
+#include "base/dependencygraph.hpp"
+#include "base/configtype.hpp"
 #include <boost/algorithm/string.hpp>
 #include <set>
 
@@ -72,11 +74,16 @@ bool StatusQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
        }
 
        BOOST_FOREACH(const ConfigObject::Ptr& obj, objs) {
+               Dictionary::Ptr result1 = new Dictionary();
+               results->Add(result1);
+
+               Dictionary::Ptr resultAttrs = new Dictionary();
+               result1->Set("attrs", resultAttrs);
+
                BOOST_FOREACH(const String& joinType, joinTypes) {
                        String prefix = joinType;
                        boost::algorithm::to_lower(prefix);
 
-                       Dictionary::Ptr result1 = new Dictionary();
                        for (int fid = 0; fid < type->GetFieldCount(); fid++) {
                                Field field = type->GetFieldInfo(fid);
                                String aname = prefix + "." + field.Name;
@@ -85,9 +92,23 @@ bool StatusQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
 
                                Value val = static_cast<Object::Ptr>(obj)->GetField(fid);
                                Value sval = Serialize(val, FAConfig | FAState);
-                               result1->Set(aname, sval);
+                               resultAttrs->Set(aname, sval);
                        }
-                       results->Add(result1);
+               }
+
+               Array::Ptr used_by = new Array();
+               result1->Set("used_by", used_by);
+
+               BOOST_FOREACH(const Object::Ptr& pobj, DependencyGraph::GetParents((obj))) {
+                       ConfigObject::Ptr configObj = dynamic_pointer_cast<ConfigObject>(pobj);
+
+                       if (!configObj)
+                               continue;
+
+                       Dictionary::Ptr refInfo = new Dictionary();
+                       refInfo->Set("type", configObj->GetType()->GetName());
+                       refInfo->Set("name", configObj->GetName());
+                       used_by->Add(refInfo);
                }
        }
 
index f6224e40669927b1e6d89350922afdcb21ce9d51..86296aa925949822fd864ff1dd033e2788023db6 100644 (file)
@@ -27,14 +27,8 @@ namespace icinga
 class Zone : ConfigObject
 {
        [config] name(Zone) parent (ParentRaw);
-       [config] Array::Ptr endpoints (EndpointsRaw);
+       [config] array(name(Endpoint)) endpoints (EndpointsRaw);
        [config] bool global;
 };
 
-validator Zone {
-       Array endpoints {
-               name(Endpoint) "*";
-       };
-};
-
 }
index 8769a8eeb002d7be3cab88d8f1e35e64c8bd3030..fb9c88ae46e104fcc6ff70208045cb4c7adfd5e0 100644 (file)
@@ -130,6 +130,7 @@ static char *lb_steal(lex_buf *lb)
 [ \t\r\n]                      /* ignore whitespace */
 
 #include                       { return T_INCLUDE; }
+#impl_include                  { return T_IMPL_INCLUDE; }
 class                          { return T_CLASS; }
 namespace                      { return T_NAMESPACE; }
 code                           { return T_CODE; }
@@ -147,9 +148,11 @@ no_storage                 { yylval->num = FANoStorage; return T_FIELD_ATTRIBUTE; }
 validator                      { return T_VALIDATOR; }
 required                       { return T_REQUIRED; }
 name                           { return T_NAME; }
+array                          { return T_ARRAY; }
 default                                { yylval->num = FTDefault; return T_FIELD_ACCESSOR_TYPE; }
 get                            { yylval->num = FTGet; return T_FIELD_ACCESSOR_TYPE; }
 set                            { yylval->num = FTSet; return T_FIELD_ACCESSOR_TYPE; }
+track                          { yylval->num = FTTrack; return T_FIELD_ACCESSOR_TYPE; }
 \"[^\"]+\"                     { yylval->text = strdup(yytext + 1); yylval->text[strlen(yylval->text) - 1] = '\0'; return T_STRING; }
 \<[^>]+\>                      { yylval->text = strdup(yytext + 1); yylval->text[strlen(yylval->text) - 1] = '\0'; return T_ANGLE_STRING; }
 [a-zA-Z_][:a-zA-Z0-9\-_]*      { yylval->text = strdup(yytext); return T_IDENTIFIER; }
index fdb6d948d7632f090fbd148e0c77f57f28006aaa..a17c0f82c0b7456f1d59131423f66a8b2e2676c1 100644 (file)
@@ -56,7 +56,8 @@ using namespace icinga;
        Validator *validator;
 }
 
-%token T_INCLUDE "include (T_INCLUDE)"
+%token T_INCLUDE "#include (T_INCLUDE)"
+%token T_IMPL_INCLUDE "#impl_include (T_IMPL_INCLUDE)"
 %token T_CLASS "class (T_CLASS)"
 %token T_CODE "code (T_CODE)"
 %token T_LOAD_AFTER "load_after (T_LOAD_AFTER)"
@@ -65,6 +66,7 @@ using namespace icinga;
 %token T_VALIDATOR "validator (T_VALIDATOR)"
 %token T_REQUIRED "required (T_REQUIRED)"
 %token T_NAME "name (T_NAME)"
+%token T_ARRAY "array (T_ARRAY)"
 %token T_STRING "string (T_STRING)"
 %token T_ANGLE_STRING "angle_string (T_ANGLE_STRING)"
 %token T_FIELD_ATTRIBUTE "field_attribute (T_FIELD_ATTRIBUTE)"
@@ -83,6 +85,8 @@ using namespace icinga;
 %type <text> type_base_specifier
 %type <text> include
 %type <text> angle_include
+%type <text> impl_include
+%type <text> angle_impl_include
 %type <text> code
 %type <num> T_FIELD_ATTRIBUTE
 %type <num> field_attribute
@@ -147,6 +151,16 @@ statement: include
                context->HandleAngleInclude($1, yylloc);
                std::free($1);
        }
+       | impl_include
+       {
+               context->HandleImplInclude($1, yylloc);
+               std::free($1);
+       }
+       | angle_impl_include
+       {
+               context->HandleAngleImplInclude($1, yylloc);
+               std::free($1);
+       }
        | class
        {
                context->HandleClass(*$1, yylloc);
@@ -178,6 +192,18 @@ angle_include: T_INCLUDE T_ANGLE_STRING
        }
        ;
 
+impl_include: T_IMPL_INCLUDE T_STRING
+       {
+               $$ = $2;
+       }
+       ;
+
+angle_impl_include: T_IMPL_INCLUDE T_ANGLE_STRING
+       {
+               $$ = $2;
+       }
+       ;
+
 namespace: T_NAMESPACE identifier '{'
        {
                context->HandleNamespaceBegin($2, yylloc);
@@ -290,8 +316,14 @@ field_type: identifier
                $$ = new FieldType();
                $$->IsName = true;
                $$->TypeName = $3;
+               $$->ArrayRank = 0;
                free($3);
        }
+       | T_ARRAY '(' field_type ')'
+       {
+               $$ = $3;
+               $$->ArrayRank++;
+       }
        ;
 
 class_field: field_attribute_list field_type identifier alternative_name_specifier field_accessor_list ';'
@@ -328,7 +360,10 @@ class_field: field_attribute_list field_type identifier alternative_name_specifi
                                case FTDefault:
                                        field->DefaultAccessor = it->Accessor;
                                        break;
-                               }
+                               case FTTrack:
+                                       field->TrackAccessor = it->Accessor;
+                                       break;
+                       }
                }
 
                delete $5;
index d079e569404533e0b1bcf0693bc5ae96cc3bedb6..12de1cbb3f613acfa4bebad0feade9de7fb7df08 100644 (file)
@@ -73,6 +73,16 @@ void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebug
        m_Header << "#include <" << path << ">" << std::endl << std::endl;
 }
 
+void ClassCompiler::HandleImplInclude(const std::string& path, const ClassDebugInfo&)
+{
+       m_Impl << "#include \"" << path << "\"" << std::endl << std::endl;
+}
+
+void ClassCompiler::HandleAngleImplInclude(const std::string& path, const ClassDebugInfo&)
+{
+       m_Impl << "#include <" << path << ">" << std::endl << std::endl;
+}
+
 void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo&)
 {
        m_Header << "namespace " << name << std::endl
@@ -356,7 +366,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
                                nameref = "NULL";
 
                        m_Impl << "\t\t" << "case " << num << ":" << std::endl
-                                << "\t\t\t" << "return Field(" << num << ", \"" << ftype << "\", \"" << it->Name << "\", " << nameref << ", " << it->Attributes << ");" << std::endl;
+                                << "\t\t\t" << "return Field(" << num << ", \"" << ftype << "\", \"" << it->Name << "\", " << nameref << ", " << it->Attributes << ", " << it->Type.ArrayRank << ");" << std::endl;
                        num++;
                }
 
@@ -454,7 +464,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
        m_Impl << "template class ObjectImpl<" << klass.Name << ">;" << std::endl << std::endl;
 
        /* Validate */
-       m_Header << "\t" << "virtual void Validate(int types, const ValidationUtils& utils);" << std::endl;
+       m_Header << "\t" << "virtual void Validate(int types, const ValidationUtils& utils) override;" << std::endl;
 
        m_Impl << "void ObjectImpl<" << klass.Name << ">::Validate(int types, const ValidationUtils& utils)" << std::endl
               << "{" << std::endl;
@@ -488,10 +498,21 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
                        }
 
                        if (field.Type.IsName) {
-                               m_Impl << "\t" << "String ref = value;" << std::endl
-                                      << "\t" << "if (!ref.IsEmpty() && !utils.ValidateName(\"" << field.Type.TypeName << "\", ref))" << std::endl
+                               if (field.Type.ArrayRank > 0) {
+                                       m_Impl << "\t" << "if (value) {" << std::endl
+                                              << "\t\t" << "ObjectLock olock(value);" << std::endl
+                                              << "\t\t" << "BOOST_FOREACH(const String& ref, value) {" << std::endl;
+                               } else
+                                       m_Impl << "\t" << "String ref = value;" << std::endl;
+
+                               m_Impl << "\t" << "if (!ref.IsEmpty() && !utils.ValidateName(\"" << field.Type.TypeName << "\", ref))" << std::endl
                                       << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Object '\" + ref + \"' of type '" << field.Type.TypeName
                                       << "' does not exist.\"));" << std::endl;
+
+                               if (field.Type.ArrayRank > 0) {
+                                       m_Impl << "\t\t" << "}" << std::endl
+                                              << "\t" << "}" << std::endl;
+                               }
                        }
                }
 
@@ -521,7 +542,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
 
                /* SetField */
                m_Header << "protected:" << std::endl
-                        << "\t" << "virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty);" << std::endl;
+                        << "\t" << "virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty) override;" << std::endl;
 
                m_Impl << "void ObjectImpl<" << klass.Name << ">::SetField(int id, const Value& value, bool suppress_events, const Value& cookie)" << std::endl
                       << "{" << std::endl;
@@ -565,7 +586,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
 
                /* GetField */
                m_Header << "protected:" << std::endl
-                        << "\t" << "virtual Value GetField(int id) const;" << std::endl;
+                        << "\t" << "virtual Value GetField(int id) const override;" << std::endl;
 
                m_Impl << "Value ObjectImpl<" << klass.Name << ">::GetField(int id) const" << std::endl
                       << "{" << std::endl;
@@ -598,7 +619,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
                
                /* ValidateField */
                m_Header << "protected:" << std::endl
-                        << "\t" << "virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils);" << std::endl;
+                        << "\t" << "virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils) override;" << std::endl;
 
                m_Impl << "void ObjectImpl<" << klass.Name << ">::ValidateField(int id, const Value& value, const ValidationUtils& utils)" << std::endl
                       << "{" << std::endl;
@@ -642,7 +663,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
 
                /* NotifyField */
                m_Header << "protected:" << std::endl
-                        << "\t" << "virtual void NotifyField(int id, const Value& cookie = Empty);" << std::endl;
+                        << "\t" << "virtual void NotifyField(int id, const Value& cookie = Empty) override;" << std::endl;
 
                m_Impl << "void ObjectImpl<" << klass.Name << ">::NotifyField(int id, const Value& cookie)" << std::endl
                       << "{" << std::endl;
@@ -723,17 +744,105 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
                                m_Impl << "void ObjectImpl<" << klass.Name << ">::Set" << it->GetFriendlyName() << "(" << it->Type.GetArgumentType() << " value, bool suppress_events, const Value& cookie)" << std::endl
                                       << "{" << std::endl;
 
+                               if (it->Type.IsName || !it->TrackAccessor.empty())
+                                       m_Impl << "\t" << "Value oldValue = Get" << it->GetFriendlyName() << "();" << std::endl;
+
+                                       
                                if (it->SetAccessor.empty() && !(it->Attributes & FANoStorage))
                                        m_Impl << "\t" << "m_" << it->GetFriendlyName() << " = value;" << std::endl;
                                else
                                        m_Impl << it->SetAccessor << std::endl << std::endl;
-                                       
+
+                               if (it->Type.IsName || !it->TrackAccessor.empty()) {
+                                       m_Impl << "\t" << "ConfigObject *dobj = dynamic_cast<ConfigObject *>(this);" << std::endl;
+
+                                       if (it->Name != "active") {
+                                               m_Impl << "\t" << "if (!dobj || dobj->IsActive())" << std::endl
+                                                      << "\t";
+                                       }
+
+                                       m_Impl << "\t" << "Track" << it->GetFriendlyName() << "(oldValue, value);" << std::endl;
+                               }
+
                                m_Impl << "\t" << "if (!suppress_events)" << std::endl
                                       << "\t\t" << "Notify" << it->GetFriendlyName() << "(cookie);" << std::endl
                                       << "}" << std::endl << std::endl;
                        }
                }
 
+               m_Header << "protected:" << std::endl;
+
+               bool needs_tracking = false;
+
+               /* tracking */
+               for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
+                       if (!it->Type.IsName && it->TrackAccessor.empty())
+                               continue;
+
+                       needs_tracking = true;
+
+                       m_Header << "\t" << "virtual void Track" << it->GetFriendlyName() << "(" << it->Type.GetArgumentType() << " oldValue, " << it->Type.GetArgumentType() << " newValue);";
+
+                       m_Impl << "void ObjectImpl<" << klass.Name << ">::Track" << it->GetFriendlyName() << "(" << it->Type.GetArgumentType() << " oldValue, " << it->Type.GetArgumentType() << " newValue)" << std::endl
+                              << "{" << std::endl;
+
+                       if (!it->TrackAccessor.empty())
+                               m_Impl << "\t" << it->TrackAccessor << std::endl;
+
+                       if (it->Type.ArrayRank > 0) {
+                               m_Impl << "\t" << "if (oldValue) {" << std::endl
+                                      << "\t\t" << "ObjectLock olock(oldValue);" << std::endl
+                                      << "\t\t" << "BOOST_FOREACH(const String& ref, oldValue) {" << std::endl
+                                      << "\t\t\t" << "DependencyGraph::RemoveDependency(this, ConfigObject::GetObject(\"" << it->Type.TypeName << "\", ref).get());" << std::endl
+                                      << "\t\t" << "}" << std::endl
+                                      << "\t" << "}" << std::endl
+                                      << "\t" << "if (newValue) {" << std::endl
+                                      << "\t\t" << "ObjectLock olock(newValue);" << std::endl
+                                      << "\t\t" << "BOOST_FOREACH(const String& ref, newValue) {" << std::endl
+                                      << "\t\t\t" << "DependencyGraph::AddDependency(this, ConfigObject::GetObject(\"" << it->Type.TypeName << "\", ref).get());" << std::endl
+                                      << "\t\t" << "}" << std::endl
+                                      << "\t" << "}" << std::endl;
+                       } else {
+                               m_Impl << "\t" << "if (!oldValue.IsEmpty())" << std::endl
+                                      << "\t\t" << "DependencyGraph::RemoveDependency(this, ConfigObject::GetObject(\"" << it->Type.TypeName << "\", oldValue).get());" << std::endl
+                                      << "\t" << "if (!newValue.IsEmpty())" << std::endl
+                                      << "\t\t" << "DependencyGraph::AddDependency(this, ConfigObject::GetObject(\"" << it->Type.TypeName << "\", newValue).get());" << std::endl;
+                       }
+
+                       m_Impl << "}" << std::endl << std::endl;
+               }
+
+               /* start/stop */
+               if (needs_tracking) {
+                       m_Header << "virtual void Start(void) override;" << std::endl
+                                << "virtual void Stop(void) override;" << std::endl;
+
+                       m_Impl << "void ObjectImpl<" << klass.Name << ">::Start(void)" << std::endl
+                              << "{" << std::endl
+                              << "\t" << klass.Parent << "::Start();" << std::endl << std::endl;
+
+                       for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
+                               if (!(it->Type.IsName))
+                                       continue;
+
+                               m_Impl << "\t" << "Track" << it->GetFriendlyName() << "(Empty, Get" << it->GetFriendlyName() << "());" << std::endl;
+                       }
+
+                       m_Impl << "}" << std::endl << std::endl
+                              << "void ObjectImpl<" << klass.Name << ">::Stop(void)" << std::endl
+                              << "{" << std::endl
+                              << "\t" << klass.Parent << "::Stop();" << std::endl << std::endl;
+
+                       for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
+                               if (!(it->Type.IsName))
+                                       continue;
+
+                               m_Impl << "\t" << "Track" << it->GetFriendlyName() << "(Get" << it->GetFriendlyName() << "(), Empty);" << std::endl;
+                       }
+
+                       m_Impl << "}" << std::endl << std::endl;
+               }
+
                /* notify */
                for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
                        std::string prot;
@@ -787,8 +896,10 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
                m_Header << "private:" << std::endl;
 
                for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
-                       if (!(it->Attributes & FANoStorage))
-                               m_Header << "\t" << it->Type.GetRealType() << " m_" << it->GetFriendlyName() << ";" << std::endl;
+                       if (it->Attributes & FANoStorage)
+                               continue;
+
+                       m_Header << "\t" << it->Type.GetRealType() << " m_" << it->GetFriendlyName() << ";" << std::endl;
                }
                
                /* signal */
@@ -1178,6 +1289,7 @@ void ClassCompiler::CompileStream(const std::string& path, std::istream& input,
              << "#include \"base/objectlock.hpp\"" << std::endl
              << "#include \"base/utility.hpp\"" << std::endl
              << "#include \"base/convert.hpp\"" << std::endl
+             << "#include \"base/dependencygraph.hpp\"" << std::endl
              << "#include <boost/foreach.hpp>" << std::endl
              << "#include <boost/assign/list_of.hpp>" << std::endl
              << "#ifdef _MSC_VER" << std::endl
index 81cf1701d6b31bb010967e69d820cd4f663ef904..db845afc491c85c6497213f531c968797b66fcf2 100644 (file)
@@ -42,7 +42,8 @@ enum FieldAccessorType
 {
        FTGet,
        FTSet,
-       FTDefault
+       FTDefault,
+       FTTrack
 };
 
 struct FieldAccessor
@@ -75,13 +76,21 @@ struct FieldType
 {
        bool IsName;
        std::string TypeName;
+       int ArrayRank;
+
+       FieldType(void)
+               : IsName(false), ArrayRank(0)
+       { }
 
        inline std::string GetRealType(void) const
        {
+               if (ArrayRank > 0)
+                       return "Array::Ptr";
+
                if (IsName)
                        return "String";
-               else
-                       return TypeName;
+
+               return TypeName;
        }
 
        inline std::string GetArgumentType(void) const
@@ -106,6 +115,7 @@ struct Field
        std::string SetAccessor;
        bool PureSetAccessor;
        std::string DefaultAccessor;
+       std::string TrackAccessor;
 
        Field(void)
                : Attributes(0), PureGetAccessor(false), PureSetAccessor(false)
@@ -203,6 +213,8 @@ public:
 
        void HandleInclude(const std::string& path, const ClassDebugInfo& locp);
        void HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp);
+       void HandleImplInclude(const std::string& path, const ClassDebugInfo& locp);
+       void HandleAngleImplInclude(const std::string& path, const ClassDebugInfo& locp);
        void HandleClass(const Klass& klass, const ClassDebugInfo& locp);
        void HandleValidator(const Validator& validator, const ClassDebugInfo& locp);
        void HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp);