Generate C++ code for type validators

fixes #7709
fixes #8867
This commit is contained in:
Gunnar Beutner 2014-11-30 23:32:13 +01:00
parent a7a0eca8b2
commit ec7224e3ed
96 changed files with 1117 additions and 2002 deletions

View File

@ -56,16 +56,6 @@ DynamicType::Ptr DynamicObject::GetType(void) const
return DynamicType::GetByName(GetTypeNameV());
}
DebugInfo DynamicObject::GetDebugInfo(void) const
{
return m_DebugInfo;
}
void DynamicObject::SetDebugInfo(const DebugInfo& di)
{
m_DebugInfo = di;
}
bool DynamicObject::IsActive(void) const
{
return GetActive();

View File

@ -52,9 +52,6 @@ public:
intrusive_ptr<DynamicType> GetType(void) const;
DebugInfo GetDebugInfo(void) const;
void SetDebugInfo(const DebugInfo& di);
bool IsActive(void) const;
bool IsPaused(void) const;
@ -97,8 +94,6 @@ protected:
private:
static DynamicObject::Ptr GetObject(const String& type, const String& name);
static void RestoreObject(const String& message, int attributeTypes);
DebugInfo m_DebugInfo;
};
#define DECLARE_OBJECTNAME(klass) \

View File

@ -33,10 +33,32 @@ public:
};
}}}
abstract class DynamicObject
abstract class DynamicObjectBase
{ };
code {{{
class I2_BASE_API DynamicObjectBase : public ObjectImpl<DynamicObjectBase>
{
public:
inline DebugInfo GetDebugInfo(void) const
{
return m_DebugInfo;
}
void SetDebugInfo(const DebugInfo& di)
{
m_DebugInfo = di;
}
private:
DebugInfo m_DebugInfo;
};
}}}
abstract class DynamicObject : DynamicObjectBase
{
[config, internal] String __name (Name);
[config] String name (ShortName) {
[config] String "name" (ShortName) {
get {{{
if (m_ShortName.IsEmpty())
return GetName();
@ -45,7 +67,7 @@ abstract class DynamicObject
}}}
};
[config, internal, get_protected] String type (TypeNameV);
[config] String zone (ZoneName);
[config] name(Zone) zone (ZoneName);
[config, internal, get_protected] Array::Ptr templates;
[get_protected] bool active;
[get_protected] bool paused {

View File

@ -18,6 +18,7 @@
******************************************************************************/
#include "base/exception.hpp"
#include "base/dynamicobject.hpp"
#include <boost/thread/tss.hpp>
#ifdef HAVE_CXXABI_H
@ -136,6 +137,8 @@ String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, Sta
String message = ex.what();
const ValidationError *vex = dynamic_cast<const ValidationError *>(&ex);
if (message.IsEmpty())
result << boost::diagnostic_information(ex);
else
@ -148,6 +151,46 @@ String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, Sta
ShowCodeFragment(result, dex->GetDebugInfo());
}
if (vex) {
DebugInfo di;
DynamicObject::Ptr dobj = dynamic_pointer_cast<DynamicObject>(vex->GetObject());
if (dobj)
di = dobj->GetDebugInfo();
Dictionary::Ptr currentHint = vex->GetDebugHint();
Array::Ptr messages;
BOOST_FOREACH(const String& attr, vex->GetAttributePath()) {
Dictionary::Ptr props = currentHint->Get("properties");
if (!props)
break;
currentHint = props->Get(attr);
if (!currentHint)
break;
messages = currentHint->Get("messages");
}
if (messages && messages->GetLength() > 0) {
Array::Ptr message = messages->Get(messages->GetLength() - 1);
di.Path = message->Get(1);
di.FirstLine = message->Get(2);
di.FirstColumn = message->Get(3);
di.LastLine = message->Get(4);
di.LastColumn = message->Get(5);
}
if (!di.Path.IsEmpty()) {
result << "\nLocation:\n";
ShowCodeFragment(result, di);
}
}
const user_error *uex = dynamic_cast<const user_error *>(&ex);
const posix_error *pex = dynamic_cast<const posix_error *>(&ex);
@ -270,3 +313,57 @@ const char *posix_error::what(void) const throw()
return m_Message;
}
ValidationError::ValidationError(const intrusive_ptr<ObjectImpl<DynamicObject> >& object, const std::vector<String>& attributePath, const String& message)
: m_Object(object), m_AttributePath(attributePath), m_Message(message)
{
String path;
BOOST_FOREACH(const String& attribute, attributePath) {
if (!path.IsEmpty())
path += " -> ";
path += "'" + attribute + "'";
}
Type::Ptr type = object->GetReflectionType();
m_What = "Validation failed for object '" + object->GetName() + "' of type '" + type->GetName() + "'";
if (!path.IsEmpty())
m_What += "; Attribute " + path;
m_What += ": " + message;
}
ValidationError::~ValidationError(void) throw()
{ }
const char *ValidationError::what(void) const throw()
{
return m_What.CStr();
}
intrusive_ptr<ObjectImpl<DynamicObject> > ValidationError::GetObject(void) const
{
return m_Object;
}
std::vector<String> ValidationError::GetAttributePath(void) const
{
return m_AttributePath;
}
String ValidationError::GetMessage(void) const
{
return m_Message;
}
void ValidationError::SetDebugHint(const Dictionary::Ptr& dhint)
{
m_DebugHint = dhint;
}
Dictionary::Ptr ValidationError::GetDebugHint(void) const
{
return m_DebugHint;
}

View File

@ -26,6 +26,7 @@
#include "base/context.hpp"
#include "base/utility.hpp"
#include "base/debuginfo.hpp"
#include "base/dictionary.hpp"
#include <sstream>
#include <boost/exception/errinfo_api_function.hpp>
#include <boost/exception/errinfo_errno.hpp>
@ -64,6 +65,35 @@ private:
bool m_IncompleteExpr;
};
class DynamicObject;
template<> class ObjectImpl<DynamicObject>;
/*
* @ingroup base
*/
class I2_BASE_API ValidationError : virtual public user_error
{
public:
ValidationError(const intrusive_ptr<ObjectImpl<DynamicObject> >& object, const std::vector<String>& attributePath, const String& message);
~ValidationError(void) throw();
virtual const char *what(void) const throw();
intrusive_ptr<ObjectImpl<DynamicObject> > GetObject(void) const;
std::vector<String> GetAttributePath(void) const;
String GetMessage(void) const;
void SetDebugHint(const Dictionary::Ptr& dhint);
Dictionary::Ptr GetDebugHint(void) const;
private:
intrusive_ptr<ObjectImpl<DynamicObject> > m_Object;
std::vector<String> m_AttributePath;
String m_Message;
String m_What;
Dictionary::Ptr m_DebugHint;
};
I2_BASE_API StackTrace *GetLastExceptionStack(void);
I2_BASE_API void SetLastExceptionStack(const StackTrace& trace);

View File

@ -24,7 +24,7 @@ namespace icinga
class FileLogger : StreamLogger
{
[config] String path;
[config, required] String path;
};
}

View File

@ -26,7 +26,6 @@
#include "base/objectlock.hpp"
#include "base/dynamictype.hpp"
#include "base/application.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <algorithm>

View File

@ -137,7 +137,7 @@ int TypeType::GetFieldId(const String& name) const
Field TypeType::GetFieldInfo(int id) const
{
if (id == 0)
return Field(0, "Object", "prototype", 0);
return Field(0, "Object", "prototype", NULL, 0);
throw std::runtime_error("Invalid field ID.");
}

View File

@ -37,6 +37,7 @@ enum FieldAttribute
FAConfig = 2,
FAState = 4,
FAInternal = 64,
FARequired = 512
};
class Type;
@ -46,10 +47,11 @@ struct Field
int ID;
const char *TypeName;
const char *Name;
const char *RefTypeName;
int Attributes;
Field(int id, const char *type, const char *name, int attributes)
: ID(id), TypeName(type), Name(name), Attributes(attributes)
Field(int id, const char *type, const char *name, const char *reftype, int attributes)
: ID(id), TypeName(type), Name(name), RefTypeName(reftype), Attributes(attributes)
{ }
};
@ -58,6 +60,12 @@ enum TypeAttribute
TAAbstract = 1
};
class ValidationUtils
{
public:
virtual bool ValidateName(const String& type, const String& name) const = 0;
};
class I2_BASE_API Type : public Object
{
public:

View File

@ -17,10 +17,8 @@
mkclass_target(checkercomponent.ti checkercomponent.thpp)
mkembedconfig_target(checker-type.conf checker-type.cpp)
set(checker_SOURCES
checkercomponent.cpp checkercomponent.thpp checker-type.cpp
checkercomponent.cpp checkercomponent.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,21 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type CheckerComponent {
}

View File

@ -26,6 +26,7 @@
#include "base/unixsocket.hpp"
#include "base/utility.hpp"
#include "base/networkstream.hpp"
#include "base/exception.hpp"
#include <iostream>
#ifdef HAVE_EDITLINE
#include "cli/editline.hpp"

View File

@ -19,8 +19,6 @@
#include "cli/repositoryutility.hpp"
#include "cli/clicommand.hpp"
#include "config/configtype.hpp"
#include "config/configcompiler.hpp"
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/convert.hpp"
@ -189,10 +187,10 @@ void RepositoryUtility::PrintChangeLog(std::ostream& fp)
}
}
class RepositoryTypeRuleUtilities : public TypeRuleUtilities
class RepositoryValidationUtils : public ValidationUtils
{
public:
virtual bool ValidateName(const String& type, const String& name, String *hint) const
virtual bool ValidateName(const String& type, const String& name) const
{
return true;
}
@ -228,31 +226,19 @@ bool RepositoryUtility::AddObject(const std::vector<String>& object_paths, const
change->Set("command", "add");
change->Set("attrs", attrs);
Type::Ptr utype = Type::GetByName(type);
ASSERT(utype);
if (check_config) {
ConfigType::Ptr ctype = ConfigType::GetByName(type);
try {
Object::Ptr object = utype->Instantiate();
Deserialize(object, attrs, false, FAConfig);
if (!ctype)
Log(LogCritical, "cli")
<< "No validation type available for '" << type << "'.";
else {
Dictionary::Ptr vattrs = attrs->ShallowClone();
vattrs->Set("__name", vattrs->Get("name"));
vattrs->Remove("name");
vattrs->Remove("import");
vattrs->Set("type", type);
Type::Ptr dtype = Type::GetByName(type);
Object::Ptr object = dtype->Instantiate();
Deserialize(object, vattrs, false, FAConfig);
try {
RepositoryTypeRuleUtilities utils;
ctype->ValidateItem(name, object, DebugInfo(), &utils);
} catch (const ScriptError& ex) {
Log(LogCritical, "config", DiagnosticInformation(ex));
return false;
}
RepositoryValidationUtils utils;
static_pointer_cast<DynamicObject>(object)->Validate(FAConfig, utils);
} catch (const ScriptError& ex) {
Log(LogCritical, "config", DiagnosticInformation(ex));
return false;
}
}

View File

@ -20,12 +20,10 @@ mkclass_target(compatlogger.ti compatlogger.thpp)
mkclass_target(externalcommandlistener.ti externalcommandlistener.thpp)
mkclass_target(statusdatawriter.ti statusdatawriter.thpp)
mkembedconfig_target(compat-type.conf compat-type.cpp)
set(compat_SOURCES
checkresultreader.cpp checkresultreader.thpp compatlogger.cpp
compatlogger.thpp externalcommandlistener.cpp externalcommandlistener.thpp
statusdatawriter.cpp statusdatawriter.thpp compat-type.cpp
statusdatawriter.cpp statusdatawriter.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,39 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type StatusDataWriter {
%attribute %string "status_path",
%attribute %string "objects_path",
%attribute %number "update_interval"
}
%type ExternalCommandListener {
%attribute %string "command_path"
}
%type CompatLogger {
%validator "ValidateRotationMethod",
%attribute %string "log_dir",
%attribute %string "rotation_method"
}
%type CheckResultReader {
%attribute %string "spool_dir"
}

View File

@ -32,7 +32,6 @@
#include "base/convert.hpp"
#include "base/application.hpp"
#include "base/utility.hpp"
#include "base/function.hpp"
#include "base/statsfunction.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
@ -40,7 +39,6 @@
using namespace icinga;
REGISTER_TYPE(CompatLogger);
REGISTER_SCRIPTFUNCTION(ValidateRotationMethod, &CompatLogger::ValidateRotationMethod);
REGISTER_STATSFUNCTION(CompatLoggerStats, &CompatLogger::StatsFunc);
@ -561,14 +559,12 @@ void CompatLogger::RotationTimerHandler(void)
ScheduleNextRotation();
}
void CompatLogger::ValidateRotationMethod(const String& location, const CompatLogger::Ptr& object)
void CompatLogger::ValidateRotationMethod(const String& value, const ValidationUtils& utils)
{
String rotation_method = object->GetRotationMethod();
ObjectImpl<CompatLogger>::ValidateRotationMethod(value, utils);
if (rotation_method != "HOURLY" && rotation_method != "DAILY" &&
rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Rotation method '" + rotation_method + "' is invalid.", object->GetDebugInfo()));
if (value != "HOURLY" && value != "DAILY" &&
value != "WEEKLY" && value != "MONTHLY" && value != "NONE") {
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("rotation_method"), "Rotation method '" + value + "' is invalid."));
}
}

View File

@ -41,7 +41,7 @@ public:
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
static void ValidateRotationMethod(const String& location, const CompatLogger::Ptr& object);
virtual void ValidateRotationMethod(const String& value, const ValidationUtils& utils) override;
protected:
virtual void Start(void);

View File

@ -31,15 +31,13 @@ endif()
add_flex_bison_dependency(config_lexer config_parser)
mkembedconfig_target(base-type.conf base-type.cpp)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
set(config_SOURCES
applyrule.cpp base-type.conf base-type.cpp
applyrule.cpp
configcompilercontext.cpp configcompiler.cpp configitembuilder.cpp
configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS}
configtype.cpp expression.cpp objectrule.cpp typerule.cpp typerulelist.cpp
expression.cpp objectrule.cpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,46 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type DynamicObject {
%require "__name",
%attribute %string "__name",
%attribute %string "name",
%require "type",
%attribute %string "type",
%attribute %name(Zone) "zone",
%attribute %array "templates" {
%attribute %string "*"
},
}
%type Logger {
%attribute %string "severity"
}
%type FileLogger %inherits Logger {
%require "path",
%attribute %string "path"
}
%type SyslogLogger %inherits Logger {
}

View File

@ -19,8 +19,8 @@
******************************************************************************/
#include "config/configcompiler.hpp"
#include "config/typerule.hpp"
#include "config/expression.hpp"
#include "base/exception.hpp"
using namespace icinga;
@ -167,19 +167,6 @@ do { \
[ \t] /* ignore whitespace */
<INITIAL>{
%type return T_TYPE;
%dictionary { yylval->type = TypeDictionary; return T_TYPE_DICTIONARY; }
%array { yylval->type = TypeArray; return T_TYPE_ARRAY; }
%number { yylval->type = TypeNumber; return T_TYPE_NUMBER; }
%string { yylval->type = TypeString; return T_TYPE_STRING; }
%scalar { yylval->type = TypeScalar; return T_TYPE_SCALAR; }
%any { yylval->type = TypeAny; return T_TYPE_ANY; }
%function { yylval->type = TypeFunction; return T_TYPE_FUNCTION; }
%name { yylval->type = TypeName; return T_TYPE_NAME; }
%validator { return T_VALIDATOR; }
%require { return T_REQUIRE; }
%attribute { return T_ATTRIBUTE; }
%inherits return T_INHERITS;
object return T_OBJECT;
template return T_TEMPLATE;
include return T_INCLUDE;

View File

@ -23,8 +23,6 @@
#include "config/i2-config.hpp"
#include "config/configitembuilder.hpp"
#include "config/configcompiler.hpp"
#include "config/typerule.hpp"
#include "config/typerulelist.hpp"
#include "config/expression.hpp"
#include "config/applyrule.hpp"
#include "config/objectrule.hpp"
@ -92,9 +90,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
bool boolean;
icinga::Expression *expr;
icinga::DictExpression *dexpr;
icinga::Value *variant;
CombinedSetOp csop;
icinga::TypeSpecifier type;
std::vector<String> *slist;
std::vector<std::pair<Expression *, EItemInfo> > *llist;
std::vector<Expression *> *elist;
@ -149,18 +145,6 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
%token T_LOCALS "locals (T_LOCALS)"
%token T_CONST "const (T_CONST)"
%token T_USE "use (T_USE)"
%token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
%token <type> T_TYPE_STRING "string (T_TYPE_STRING)"
%token <type> T_TYPE_SCALAR "scalar (T_TYPE_SCALAR)"
%token <type> T_TYPE_ANY "any (T_TYPE_ANY)"
%token <type> T_TYPE_FUNCTION "function (T_TYPE_FUNCTION)"
%token <type> T_TYPE_NAME "name (T_TYPE_NAME)"
%token T_VALIDATOR "%validator (T_VALIDATOR)"
%token T_REQUIRE "%require (T_REQUIRE)"
%token T_ATTRIBUTE "%attribute (T_ATTRIBUTE)"
%token T_TYPE "type (T_TYPE)"
%token T_OBJECT "object (T_OBJECT)"
%token T_TEMPLATE "template (T_TEMPLATE)"
%token T_INCLUDE "include (T_INCLUDE)"
@ -190,9 +174,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
%type <elist> rterm_items_inner
%type <slist> identifier_items
%type <slist> identifier_items_inner
%type <variant> typerulelist
%type <csop> combined_set_op
%type <type> type
%type <llist> statements
%type <llist> lterm_items
%type <llist> lterm_items_inner
@ -352,106 +334,6 @@ identifier: T_IDENTIFIER
| T_STRING
;
type: T_TYPE identifier
{
String name = String($2);
free($2);
context->m_Type = ConfigType::GetByName(name);
if (!context->m_Type) {
context->m_Type = new ConfigType(name, @$);
context->m_Type->Register();
}
}
type_inherits_specifier typerulelist
{
TypeRuleList::Ptr ruleList = *$5;
delete $5;
context->m_Type->GetRuleList()->AddRules(ruleList);
context->m_Type->GetRuleList()->AddRequires(ruleList);
BOOST_FOREACH(const String& validator, ruleList->GetValidators()) {
context->m_Type->GetRuleList()->AddValidator(validator);
}
}
;
typerulelist: '{'
{
context->m_OpenBraces++;
context->m_RuleLists.push(new TypeRuleList());
}
typerules
'}'
{
context->m_OpenBraces--;
$$ = new Value(context->m_RuleLists.top());
context->m_RuleLists.pop();
}
;
typerules: typerules_inner
| typerules_inner sep
typerules_inner: /* empty */
| typerule
| typerules_inner sep typerule
;
typerule: T_REQUIRE T_STRING
{
context->m_RuleLists.top()->AddRequire($2);
free($2);
}
| T_VALIDATOR T_STRING
{
context->m_RuleLists.top()->AddValidator($2);
free($2);
}
| T_ATTRIBUTE type T_STRING
{
TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), @$);
free($3);
context->m_RuleLists.top()->AddRule(rule);
}
| T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
{
TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), @$);
free($4);
free($6);
context->m_RuleLists.top()->AddRule(rule);
}
| T_ATTRIBUTE type T_STRING typerulelist
{
TypeRule rule($2, String(), $3, *$4, @$);
free($3);
delete $4;
context->m_RuleLists.top()->AddRule(rule);
}
;
type_inherits_specifier: /* empty */
| T_INHERITS identifier
{
context->m_Type->SetParent($2);
free($2);
}
;
type: T_TYPE_DICTIONARY
| T_TYPE_ARRAY
| T_TYPE_NUMBER
| T_TYPE_STRING
| T_TYPE_SCALAR
| T_TYPE_ANY
| T_TYPE_FUNCTION
| T_TYPE_NAME
;
object:
{
context->m_ObjectAssign.push(true);
@ -483,7 +365,7 @@ object:
if (seen_assign) {
if (!ObjectRule::IsValidSourceType(type))
BOOST_THROW_EXCEPTION(ScriptError("object rule 'assign' cannot be used for type '" + type + "'", DebugInfoRange(@2, @3)));
BOOST_THROW_EXCEPTION(ScriptError("object rule 'assign' cannot be used for type '" + type + "'", DebugInfoRange(@2, @4)));
if (ignore) {
Expression *rex = new LogicalNegateExpression(ignore, DebugInfoRange(@2, @5));
@ -544,11 +426,7 @@ combined_set_op: T_SET
| T_SET_BINARY_OR
;
lterm: type
{
$$ = MakeLiteral(); // ASTify this
}
| library
lterm: library
{
$$ = MakeLiteral(); // ASTify this
}

View File

@ -22,7 +22,6 @@
#include "config/i2-config.hpp"
#include "config/expression.hpp"
#include "config/configtype.hpp"
#include "base/debuginfo.hpp"
#include "base/registry.hpp"
#include "base/initialize.hpp"
@ -124,9 +123,6 @@ public:
std::ostringstream m_LexBuffer;
CompilerDebugInfo m_LocationBegin;
std::stack<TypeRuleList::Ptr> m_RuleLists;
ConfigType::Ptr m_Type;
std::stack<bool> m_Apply;
std::stack<bool> m_ObjectAssign;
std::stack<bool> m_SeenAssign;

View File

@ -21,7 +21,6 @@
#include "config/configcompilercontext.hpp"
#include "config/applyrule.hpp"
#include "config/objectrule.hpp"
#include "config/configtype.hpp"
#include "base/application.hpp"
#include "base/dynamictype.hpp"
#include "base/objectlock.hpp"
@ -135,6 +134,15 @@ boost::shared_ptr<Expression> ConfigItem::GetFilter(void) const
return m_Filter;
}
class DefaultValidationUtils : public ValidationUtils
{
public:
virtual bool ValidateName(const String& type, const String& name) const override
{
return ConfigItem::GetObject(type, name) != ConfigItem::Ptr();
}
};
/**
* Commits the configuration item by creating a DynamicObject
* object.
@ -210,7 +218,9 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard)
persistentItem->Set("type", GetType());
persistentItem->Set("name", GetName());
persistentItem->Set("properties", Serialize(dobj, FAConfig));
persistentItem->Set("debug_hints", debugHints.ToDictionary());
Dictionary::Ptr dhint = debugHints.ToDictionary();
persistentItem->Set("debug_hints", dhint);
Array::Ptr di = new Array();
di->Add(m_DebugInfo.Path);
@ -223,13 +233,16 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard)
ConfigCompilerContext::GetInstance()->WriteObject(persistentItem);
persistentItem.reset();
ConfigType::Ptr ctype = ConfigType::GetByName(GetType());
if (ctype) {
TypeRuleUtilities utils;
ctype->ValidateItem(GetName(), dobj, GetDebugInfo(), &utils);
try {
DefaultValidationUtils utils;
dobj->Validate(FAConfig, utils);
} catch (ValidationError& ex) {
ex.SetDebugHint(dhint);
throw;
}
dhint.reset();
dobj->Register();
m_Object = dobj;

View File

@ -1,271 +0,0 @@
/******************************************************************************
* 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 "config/configtype.hpp"
#include "config/vmops.hpp"
#include "base/objectlock.hpp"
#include "base/convert.hpp"
#include "base/singleton.hpp"
#include "base/function.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
ConfigType::ConfigType(const String& name, const DebugInfo& debuginfo)
: m_Name(name), m_RuleList(new TypeRuleList()), m_DebugInfo(debuginfo)
{ }
String ConfigType::GetName(void) const
{
return m_Name;
}
String ConfigType::GetParent(void) const
{
return m_Parent;
}
void ConfigType::SetParent(const String& parent)
{
m_Parent = parent;
}
TypeRuleList::Ptr ConfigType::GetRuleList(void) const
{
return m_RuleList;
}
DebugInfo ConfigType::GetDebugInfo(void) const
{
return m_DebugInfo;
}
void ConfigType::AddParentRules(std::vector<TypeRuleList::Ptr>& ruleLists, const ConfigType::Ptr& item)
{
ConfigType::Ptr parent;
if (item->m_Parent.IsEmpty()) {
if (item->GetName() != "DynamicObject")
parent = ConfigType::GetByName("DynamicObject");
} else {
parent = ConfigType::GetByName(item->m_Parent);
}
if (parent) {
AddParentRules(ruleLists, parent);
ruleLists.push_back(parent->m_RuleList);
}
}
void ConfigType::ValidateItem(const String& name, const Object::Ptr& object, const DebugInfo& debugInfo, const TypeRuleUtilities *utils)
{
String location = "Object '" + name + "' (Type: '" + GetName() + "')";
if (!debugInfo.Path.IsEmpty())
location += " at " + debugInfo.Path + ":" + Convert::ToString(debugInfo.FirstLine);
std::vector<String> locations;
locations.push_back(location);
std::vector<TypeRuleList::Ptr> ruleLists;
AddParentRules(ruleLists, this);
ruleLists.push_back(m_RuleList);
ValidateObject(object, ruleLists, locations, utils);
}
String ConfigType::LocationToString(const std::vector<String>& locations)
{
bool first = true;
String stack;
BOOST_FOREACH(const String& location, locations) {
if (!first)
stack += " -> ";
else
first = false;
stack += location;
}
return stack;
}
void ConfigType::ValidateAttribute(const String& key, const Value& value,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils)
{
TypeValidationResult overallResult = ValidationUnknownField;
std::vector<TypeRuleList::Ptr> subRuleLists;
String hint;
locations.push_back("Key " + key);
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
TypeRuleList::Ptr subRuleList;
TypeValidationResult result = ruleList->ValidateAttribute(key, value, &subRuleList, &hint, utils);
if (subRuleList)
subRuleLists.push_back(subRuleList);
if (overallResult == ValidationOK)
continue;
if (result == ValidationOK) {
overallResult = result;
continue;
}
if (result == ValidationInvalidType)
overallResult = result;
}
if (overallResult == ValidationUnknownField)
BOOST_THROW_EXCEPTION(ScriptError("Unknown attribute: " + LocationToString(locations)));
else if (overallResult == ValidationInvalidType) {
String message = "Invalid value: " + LocationToString(locations);
if (!hint.IsEmpty())
message += ": " + hint;
BOOST_THROW_EXCEPTION(ScriptError(message));
}
if (!subRuleLists.empty() && value.IsObject() && !value.IsObjectType<Array>())
ValidateObject(value, subRuleLists, locations, utils);
else if (!subRuleLists.empty() && value.IsObjectType<Array>())
ValidateArray(value, subRuleLists, locations, utils);
locations.pop_back();
}
void ConfigType::ValidateObject(const Object::Ptr& object,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils)
{
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
BOOST_FOREACH(const String& require, ruleList->GetRequires()) {
locations.push_back("Attribute '" + require + "'");
Value value = VMOps::GetField(object, require);
if (value.IsEmpty())
BOOST_THROW_EXCEPTION(ScriptError("Required attribute is missing: " + LocationToString(locations)));
locations.pop_back();
}
BOOST_FOREACH(const String& validator, ruleList->GetValidators()) {
Function::Ptr func = ScriptGlobal::Get(validator, &Empty);
if (!func)
BOOST_THROW_EXCEPTION(std::invalid_argument("Validator function '" + validator + "' does not exist."));
std::vector<Value> arguments;
arguments.push_back(LocationToString(locations));
arguments.push_back(object);
func->Invoke(arguments);
}
}
Dictionary::Ptr dictionary = dynamic_pointer_cast<Dictionary>(object);
if (dictionary) {
ObjectLock olock(dictionary);
BOOST_FOREACH(const Dictionary::Pair& kv, dictionary) {
ValidateAttribute(kv.first, kv.second, ruleLists, locations, utils);
}
} else {
Type::Ptr type = object->GetReflectionType();
if (!type)
return;
for (int i = 0; i < type->GetFieldCount(); i++) {
Field field = type->GetFieldInfo(i);
if (!(field.Attributes & FAConfig))
continue;
ValidateAttribute(field.Name, object->GetField(i), ruleLists, locations, utils);
}
}
}
void ConfigType::ValidateArray(const Array::Ptr& array,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils)
{
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
BOOST_FOREACH(const String& require, ruleList->GetRequires()) {
size_t index = Convert::ToLong(require);
locations.push_back("Attribute '" + require + "'");
if (array->GetLength() < index)
BOOST_THROW_EXCEPTION(ScriptError("Required array index is missing: " + LocationToString(locations)));
locations.pop_back();
}
BOOST_FOREACH(const String& validator, ruleList->GetValidators()) {
Function::Ptr func = ScriptGlobal::Get(validator, &Empty);
if (!func)
BOOST_THROW_EXCEPTION(std::invalid_argument("Validator function '" + validator + "' does not exist."));
std::vector<Value> arguments;
arguments.push_back(LocationToString(locations));
arguments.push_back(array);
func->Invoke(arguments);
}
}
ObjectLock olock(array);
int index = 0;
String key;
BOOST_FOREACH(const Value& value, array) {
key = Convert::ToString(index);
index++;
ValidateAttribute(key, value, ruleLists, locations, utils);
}
}
void ConfigType::Register(void)
{
ConfigTypeRegistry::GetInstance()->Register(GetName(), this);
}
ConfigType::Ptr ConfigType::GetByName(const String& name)
{
return ConfigTypeRegistry::GetInstance()->GetItem(name);
}
ConfigTypeRegistry::ItemMap ConfigType::GetTypes(void)
{
return ConfigTypeRegistry::GetInstance()->GetItems();
}
ConfigTypeRegistry *ConfigTypeRegistry::GetInstance(void)
{
return Singleton<ConfigTypeRegistry>::GetInstance();
}

View File

@ -1,90 +0,0 @@
/******************************************************************************
* 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 CONFIGTYPE_H
#define CONFIGTYPE_H
#include "config/i2-config.hpp"
#include "config/typerulelist.hpp"
#include "config/typerule.hpp"
#include "config/configitem.hpp"
#include "base/array.hpp"
#include "base/registry.hpp"
namespace icinga
{
/**
* A configuration type. Used to validate config objects.
*
* @ingroup config
*/
class I2_CONFIG_API ConfigType : public Object {
public:
DECLARE_PTR_TYPEDEFS(ConfigType);
ConfigType(const String& name, const DebugInfo& debuginfo);
String GetName(void) const;
String GetParent(void) const;
void SetParent(const String& parent);
TypeRuleList::Ptr GetRuleList(void) const;
DebugInfo GetDebugInfo(void) const;
void ValidateItem(const String& name, const Object::Ptr& object,
const DebugInfo& debugInfo, const TypeRuleUtilities *utils);
void Register(void);
static ConfigType::Ptr GetByName(const String& name);
static Registry<ConfigType, ConfigType::Ptr>::ItemMap GetTypes(void);
private:
String m_Name; /**< The type name. */
String m_Parent; /**< The parent type. */
TypeRuleList::Ptr m_RuleList;
DebugInfo m_DebugInfo; /**< Debug information. */
static void ValidateAttribute(const String& key, const Value& value,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils);
static void ValidateObject(const Object::Ptr& object,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils);
static void ValidateArray(const Array::Ptr& array,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils);
static String LocationToString(const std::vector<String>& locations);
static void AddParentRules(std::vector<TypeRuleList::Ptr>& ruleLists, const ConfigType::Ptr& item);
};
class I2_CONFIG_API ConfigTypeRegistry : public Registry<ConfigTypeRegistry, ConfigType::Ptr>
{
public:
static ConfigTypeRegistry *GetInstance(void);
};
}
#endif /* CONFIGTYPE_H */

View File

@ -1,108 +0,0 @@
/******************************************************************************
* 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 "config/typerule.hpp"
#include "config/configitem.hpp"
#include "base/convert.hpp"
#include "base/utility.hpp"
#include "base/dictionary.hpp"
#include "base/array.hpp"
using namespace icinga;
TypeRule::TypeRule(TypeSpecifier type, const String& nameType,
const String& namePattern, const TypeRuleList::Ptr& subRules,
const DebugInfo& debuginfo)
: m_Type(type), m_NameType(nameType), m_NamePattern(namePattern), m_SubRules(subRules), m_DebugInfo(debuginfo)
{ }
TypeRuleList::Ptr TypeRule::GetSubRules(void) const
{
return m_SubRules;
}
bool TypeRule::MatchName(const String& name) const
{
return (Utility::Match(m_NamePattern, name));
}
bool TypeRule::MatchValue(const Value& value, String *hint, const TypeRuleUtilities *utils) const
{
ConfigItem::Ptr item;
if (value.IsEmpty())
return true;
switch (m_Type) {
case TypeAny:
return true;
case TypeString:
/* fall through; any scalar can be converted to a string */
case TypeScalar:
return value.IsScalar();
case TypeNumber:
try {
Convert::ToDouble(value);
} catch (...) {
return false;
}
return true;
case TypeDictionary:
return value.IsObjectType<Dictionary>();
case TypeArray:
return value.IsObjectType<Array>();
case TypeFunction:
return value.IsObjectType<Function>();
case TypeName:
if (!value.IsScalar())
return false;
return utils->ValidateName(m_NameType, value, hint);
default:
return false;
}
}
bool TypeRuleUtilities::ValidateName(const String& type, const String& name, String *hint) const
{
if (name.IsEmpty())
return true;
ConfigItem::Ptr item = ConfigItem::GetObject(type, name);
if (!item) {
*hint = "Object '" + name + "' of type '" + type + "' does not exist.";
return false;
}
if (item->IsAbstract()) {
*hint = "Object '" + name + "' of type '" + type + "' must not be a template.";
return false;
}
return true;
}

View File

@ -1,85 +0,0 @@
/******************************************************************************
* 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 TYPERULE_H
#define TYPERULE_H
#include "config/i2-config.hpp"
#include "config/typerulelist.hpp"
#include "base/debuginfo.hpp"
namespace icinga
{
/**
* Utilities for type rules.
*
* @ingroup config
*/
class I2_CONFIG_API TypeRuleUtilities
{
public:
virtual bool ValidateName(const String& type, const String& name, String *hint) const;
};
/**
* The allowed type for a type rule.
*
* @ingroup config
*/
enum TypeSpecifier
{
TypeAny,
TypeScalar,
TypeNumber,
TypeString,
TypeDictionary,
TypeArray,
TypeFunction,
TypeName
};
/**
* A configuration type rule.
*
* @ingroup config
*/
struct I2_CONFIG_API TypeRule
{
public:
TypeRule(TypeSpecifier type, const String& nameType,
const String& namePattern, const TypeRuleList::Ptr& subRules,
const DebugInfo& debuginfo);
TypeRuleList::Ptr GetSubRules(void) const;
bool MatchName(const String& name) const;
bool MatchValue(const Value& value, String *hint, const TypeRuleUtilities *utils) const;
private:
TypeSpecifier m_Type;
String m_NameType;
String m_NamePattern;
TypeRuleList::Ptr m_SubRules;
DebugInfo m_DebugInfo;
};
}
#endif /* TYPERULE_H */

View File

@ -1,140 +0,0 @@
/******************************************************************************
* 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 "config/typerulelist.hpp"
#include "config/typerule.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
/**
* Adds a validator method for a rule list.
*
* @param validator The validator.
*/
void TypeRuleList::AddValidator(const String& validator)
{
m_Validators.push_back(validator);
}
/**
* Retrieves the validator methods.
*
* @returns The validator methods.
*/
std::vector<String> TypeRuleList::GetValidators(void) const
{
return m_Validators;
}
/**
* Adds an attribute to the list of required attributes.
*
* @param attr The new required attribute.
*/
void TypeRuleList::AddRequire(const String& attr)
{
m_Requires.push_back(attr);
}
/**
* Retrieves the list of required attributes.
*
* @returns The list of required attributes.
*/
std::vector<String> TypeRuleList::GetRequires(void) const
{
return m_Requires;
}
/**
* Adds all requires from the specified rule list.
*
* @param ruleList The rule list to copy requires from.
*/
void TypeRuleList::AddRequires(const TypeRuleList::Ptr& ruleList)
{
BOOST_FOREACH(const String& require, ruleList->m_Requires) {
AddRequire(require);
}
}
/**
* Adds a rule to a rule list.
*
* @param rule The rule that should be added.
*/
void TypeRuleList::AddRule(const TypeRule& rule)
{
m_Rules.push_back(rule);
}
/**
* Adds all rules from the specified rule list.
*
* @param ruleList The rule list to copy rules from.
*/
void TypeRuleList::AddRules(const TypeRuleList::Ptr& ruleList)
{
BOOST_FOREACH(const TypeRule& rule, ruleList->m_Rules) {
AddRule(rule);
}
}
/**
* Returns the number of rules currently contained in the list.
*
* @returns The length of the list.
*/
size_t TypeRuleList::GetLength(void) const
{
return m_Rules.size();
}
/**
* Validates a field.
*
* @param name The name of the attribute.
* @param value The value of the attribute.
* @param[out] subRules The list of sub-rules for the matching rule.
* @param[out] hint A hint describing the validation failure.
* @returns The validation result.
*/
TypeValidationResult TypeRuleList::ValidateAttribute(const String& name,
const Value& value, TypeRuleList::Ptr *subRules, String *hint,
const TypeRuleUtilities *utils) const
{
bool foundField = false;
BOOST_FOREACH(const TypeRule& rule, m_Rules) {
if (!rule.MatchName(name))
continue;
foundField = true;
if (rule.MatchValue(value, hint, utils)) {
*subRules = rule.GetSubRules();
return ValidationOK;
}
}
if (foundField)
return ValidationInvalidType;
else
return ValidationUnknownField;
}

View File

@ -1,76 +0,0 @@
/******************************************************************************
* 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 TYPERULELIST_H
#define TYPERULELIST_H
#include "config/i2-config.hpp"
#include "base/value.hpp"
#include <vector>
namespace icinga
{
struct TypeRule;
class TypeRuleUtilities;
/**
* @ingroup config
*/
enum TypeValidationResult
{
ValidationOK,
ValidationInvalidType,
ValidationUnknownField
};
/**
* A list of configuration type rules.
*
* @ingroup config
*/
class I2_CONFIG_API TypeRuleList : public Object
{
public:
DECLARE_PTR_TYPEDEFS(TypeRuleList);
void AddValidator(const String& validator);
std::vector<String> GetValidators(void) const;
void AddRequire(const String& attr);
void AddRequires(const TypeRuleList::Ptr& ruleList);
std::vector<String> GetRequires(void) const;
void AddRule(const TypeRule& rule);
void AddRules(const TypeRuleList::Ptr& ruleList);
TypeValidationResult ValidateAttribute(const String& name, const Value& value,
TypeRuleList::Ptr *subRules, String *hint, const TypeRuleUtilities *utils) const;
size_t GetLength(void) const;
private:
std::vector<String> m_Validators;
std::vector<String> m_Requires;
std::vector<TypeRule> m_Rules;
};
}
#endif /* TYPERULELIST_H */

View File

@ -317,9 +317,13 @@ public:
try {
context->SetField(fid, value);
} catch (const boost::bad_lexical_cast&) {
BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'", debugInfo));
Field fieldInfo = type->GetFieldInfo(fid);
Type::Ptr ftype = Type::GetByName(fieldInfo.TypeName);
BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "', expected '" + ftype->GetName() + "'", debugInfo));
} catch (const std::bad_cast&) {
BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'", debugInfo));
Field fieldInfo = type->GetFieldInfo(fid);
Type::Ptr ftype = Type::GetByName(fieldInfo.TypeName);
BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "', expected '" + ftype->GetName() + "'", debugInfo));
}
}

View File

@ -17,12 +17,11 @@
mkclass_target(dbconnection.ti dbconnection.thpp)
mkembedconfig_target(db_ido-type.conf db_ido-type.cpp)
mkembedconfig_target(db_ido-itl.conf db_ido-itl.cpp)
set(db_ido_SOURCES
commanddbobject.cpp dbconnection.cpp dbconnection.thpp dbconnection.thpp
db_ido-type.cpp db_ido-itl.cpp dbevents.cpp dbobject.cpp dbquery.cpp
db_ido-itl.cpp dbevents.cpp dbobject.cpp dbquery.cpp
dbreference.cpp dbtype.cpp dbvalue.cpp endpointdbobject.cpp hostdbobject.cpp
hostgroupdbobject.cpp idochecktask.cpp servicedbobject.cpp
servicegroupdbobject.cpp timeperioddbobject.cpp userdbobject.cpp

View File

@ -1,48 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type DbConnection {
%validator "ValidateFailoverTimeout"
%attribute %string "table_prefix",
%attribute %dictionary "cleanup" {
%attribute %number "acknowledgements_age",
%attribute %number "commenthistory_age",
%attribute %number "contactnotifications_age",
%attribute %number "contactnotificationmethods_age",
%attribute %number "downtimehistory_age",
%attribute %number "eventhandlers_age",
%attribute %number "externalcommands_age",
%attribute %number "flappinghistory_age",
%attribute %number "hostchecks_age",
%attribute %number "logentries_age",
%attribute %number "notifications_age",
%attribute %number "processevents_age",
%attribute %number "statehistory_age",
%attribute %number "servicechecks_age",
%attribute %number "systemcommands_age",
},
%attribute %number "categories",
%attribute %number "enable_ha",
%attribute %number "failover_timeout",
}

View File

@ -27,14 +27,12 @@
#include "base/objectlock.hpp"
#include "base/utility.hpp"
#include "base/logger.hpp"
#include "base/function.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
REGISTER_TYPE(DbConnection);
REGISTER_SCRIPTFUNCTION(ValidateFailoverTimeout, &DbConnection::ValidateFailoverTimeout);
Timer::Ptr DbConnection::m_ProgramStatusTimer;
boost::once_flag DbConnection::m_OnceFlag = BOOST_ONCE_INIT;
@ -440,12 +438,12 @@ void DbConnection::PrepareDatabase(void)
}
}
void DbConnection::ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object)
void DbConnection::ValidateFailoverTimeout(double value, const ValidationUtils& utils)
{
if (object->GetFailoverTimeout() < 60) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Failover timeout minimum is 60s.", object->GetDebugInfo()));
}
ObjectImpl<DbConnection>::ValidateFailoverTimeout(value, utils);
if (value < 60)
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("failover_timeout"), "Failover timeout minimum is 60s."));
}
void DbConnection::IncreaseQueryCount(void)

View File

@ -74,7 +74,7 @@ public:
int GetQueryCount(RingBuffer::SizeType span) const;
virtual int GetPendingQueryCount(void) const = 0;
static void ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object);
virtual void ValidateFailoverTimeout(double value, const ValidationUtils& utils) override;
protected:
virtual void OnConfigLoaded(void);

View File

@ -56,4 +56,25 @@ abstract class DbConnection : DynamicObject
};
};
validator DbConnection {
Dictionary cleanup {
Number acknowledgements_age;
Number commenthistory_age;
Number contactnotifications_age;
Number contactnotificationmethods_age;
Number downtimehistory_age;
Number eventhandlers_age;
Number externalcommands_age;
Number flappinghistory_age;
Number hostchecks_age;
Number logentries_age;
Number notifications_age;
Number processevents_age;
Number statehistory_age;
Number servicechecks_age;
Number systemcommands_age;
};
};
}

View File

@ -20,10 +20,8 @@ find_package(MySQL)
if(MYSQL_FOUND)
mkclass_target(idomysqlconnection.ti idomysqlconnection.thpp)
mkembedconfig_target(db_ido_mysql-type.conf db_ido_mysql-type.cpp)
set(db_ido_mysql_SOURCES
idomysqlconnection.cpp idomysqlconnection.thpp db_ido_mysql-type.cpp
idomysqlconnection.cpp idomysqlconnection.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,33 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type IdoMysqlConnection %inherits DbConnection {
%attribute %string "host",
%attribute %number "port",
%attribute %string "socket_path",
%attribute %string "user",
%attribute %string "password",
%attribute %string "database",
%attribute %string "instance_name",
%attribute %string "instance_description"
}

View File

@ -20,13 +20,11 @@ find_package(PostgreSQL)
if(PostgreSQL_FOUND)
mkclass_target(idopgsqlconnection.ti idopgsqlconnection.thpp)
mkembedconfig_target(db_ido_pgsql-type.conf db_ido_pgsql-type.cpp)
link_directories(${PostgreSQL_LIBRARY_DIRS})
include_directories(${PostgreSQL_INCLUDE_DIRS})
set(db_ido_pgsql_SOURCES
idopgsqlconnection.cpp idopgsqlconnection.thpp db_ido_pgsql-type.cpp
idopgsqlconnection.cpp idopgsqlconnection.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,31 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type IdoPgsqlConnection %inherits DbConnection {
%attribute %string "host",
%attribute %number "port",
%attribute %string "user",
%attribute %string "password",
%attribute %string "database",
%attribute %string "instance_name",
%attribute %string "instance_description"
}

View File

@ -17,10 +17,8 @@
mkclass_target(demo.ti demo.thpp)
mkembedconfig_target(demo-type.conf demo-type.cpp)
set(demo_SOURCES
demo.cpp demo.thpp demo-type.cpp
demo.cpp demo.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,21 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type Demo {
}

View File

@ -17,11 +17,10 @@
mkclass_target(hello.ti hello.thpp)
mkembedconfig_target(hello-type.conf hello-type.cpp)
mkembedconfig_target(hello-app.conf hello-app.cpp)
set(hello_SOURCES
hello.cpp hello.thpp hello-type.cpp hello-app.cpp
hello.cpp hello.thpp hello-app.cpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,21 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type Hello {
}

View File

@ -38,7 +38,6 @@ mkclass_target(timeperiod.ti timeperiod.thpp)
mkclass_target(usergroup.ti usergroup.thpp)
mkclass_target(user.ti user.thpp)
mkembedconfig_target(icinga-type.conf icinga-type.cpp)
mkembedconfig_target(icinga-app.conf icinga-app.cpp)
set(icinga_SOURCES
@ -52,7 +51,7 @@ set(icinga_SOURCES
notification.thpp notification-apply.cpp objectutils.cpp perfdatavalue.cpp perfdatavalue.thpp pluginutility.cpp scheduleddowntime.cpp
scheduleddowntime.thpp scheduleddowntime-apply.cpp service-apply.cpp checkable-check.cpp checkable-comment.cpp
service.cpp service.thpp servicegroup.cpp servicegroup.thpp checkable-notification.cpp timeperiod.cpp timeperiod.thpp
user.cpp user.thpp usergroup.cpp usergroup.thpp icinga-type.cpp icinga-app.cpp
user.cpp user.thpp usergroup.cpp usergroup.thpp icinga-app.cpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -20,7 +20,6 @@
#include "icinga/checkable.hpp"
#include "base/objectlock.hpp"
#include "base/utility.hpp"
#include "base/function.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
#include <boost/bind/apply.hpp>
@ -28,7 +27,6 @@
using namespace icinga;
REGISTER_TYPE(Checkable);
REGISTER_SCRIPTFUNCTION(ValidateCheckableCheckInterval, &Checkable::ValidateCheckInterval);
boost::signals2::signal<void (const Checkable::Ptr&, bool, const MessageOrigin&)> Checkable::OnEnablePerfdataChanged;
boost::signals2::signal<void (const Checkable::Ptr&, const String&, const String&, AcknowledgementType, bool, double, const MessageOrigin&)> Checkable::OnAcknowledgementSet;
@ -263,10 +261,10 @@ Endpoint::Ptr Checkable::GetCommandEndpoint(void) const
return Endpoint::GetByName(GetCommandEndpointRaw());
}
void Checkable::ValidateCheckInterval(const String& location, const Checkable::Ptr& object)
void Checkable::ValidateCheckIntervalRaw(double value, const ValidationUtils& utils)
{
if (object->GetCheckInterval() <= 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": check_interval must be greater than 0.", object->GetDebugInfo()));
}
ObjectImpl<Checkable>::ValidateCheckIntervalRaw(value, utils);
if (value <= 0)
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("check_interval"), "Interval must be greater than 0."));
}

View File

@ -277,7 +277,7 @@ public:
void RemoveReverseDependency(const intrusive_ptr<Dependency>& dep);
std::set<intrusive_ptr<Dependency> > GetReverseDependencies(void) const;
static void ValidateCheckInterval(const String& location, const Checkable::Ptr& object);
virtual void ValidateCheckIntervalRaw(double value, const ValidationUtils& utils) override;
protected:
virtual void Start(void);

View File

@ -43,18 +43,18 @@ abstract class Checkable : CustomVarObject
[config] Array::Ptr groups {
default {{{ return new Array(); }}}
};
[config, protected] String check_command (CheckCommandRaw);
[config, protected, required] name(CheckCommand) check_command (CheckCommandRaw);
[config] int max_check_attempts (MaxCheckAttemptsRaw) {
default {{{ return 3; }}}
};
[config, protected] String check_period (CheckPeriodRaw);
[config, protected] name(TimePeriod) check_period (CheckPeriodRaw);
[config] double check_interval (CheckIntervalRaw) {
default {{{ return 5 * 60; }}}
};
[config] double retry_interval (RetryIntervalRaw) {
default {{{ return 60; }}}
};
[config] String event_command (EventCommandRaw);
[config] name(EventCommand) event_command (EventCommandRaw);
[config] bool volatile;
[config] double flapping_threshold {
default {{{ return 30; }}}
@ -147,7 +147,7 @@ abstract class Checkable : CustomVarObject
[state] Value override_max_check_attempts;
[state] Value override_check_period;
[config] String command_endpoint (CommandEndpointRaw);
[config] name(Endpoint) command_endpoint (CommandEndpointRaw);
};
}

View File

@ -19,7 +19,6 @@
#include "icinga/command.hpp"
#include "icinga/macroprocessor.hpp"
#include "base/function.hpp"
#include "base/exception.hpp"
#include "base/objectlock.hpp"
#include <boost/foreach.hpp>
@ -27,9 +26,6 @@
using namespace icinga;
REGISTER_TYPE(Command);
REGISTER_SCRIPTFUNCTION(ValidateCommandAttributes, &Command::ValidateAttributes);
REGISTER_SCRIPTFUNCTION(ValidateCommandArguments, &Command::ValidateArguments);
REGISTER_SCRIPTFUNCTION(ValidateEnvironmentVariables, &Command::ValidateEnvironmentVariables);
int Command::GetModifiedAttributes(void) const
{
@ -49,81 +45,68 @@ void Command::SetModifiedAttributes(int flags, const MessageOrigin& origin)
}
}
void Command::ValidateAttributes(const String& location, const Command::Ptr& object)
void Command::Validate(int types, const ValidationUtils& utils)
{
if (object->GetArguments() != Empty && !object->GetCommandLine().IsObjectType<Array>()) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Attribute 'command' must be an array if the 'arguments' attribute is set.", object->GetDebugInfo()));
}
}
ObjectImpl<Command>::Validate(types, utils);
void Command::ValidateArguments(const String& location, const Command::Ptr& object)
{
Dictionary::Ptr arguments = object->GetArguments();
Dictionary::Ptr arguments = GetArguments();
if (!arguments)
if (!(types & FAConfig))
return;
ObjectLock olock(arguments);
BOOST_FOREACH(const Dictionary::Pair& kv, arguments) {
const Value& arginfo = kv.second;
Value argval;
if (arguments) {
if (!GetCommandLine().IsObjectType<Array>())
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("command"), "Attribute 'command' must be an array if the 'arguments' attribute is set."));
if (arginfo.IsObjectType<Dictionary>()) {
Dictionary::Ptr argdict = arginfo;
ObjectLock olock(arguments);
BOOST_FOREACH(const Dictionary::Pair& kv, arguments) {
const Value& arginfo = kv.second;
Value argval;
if (argdict->Contains("value")) {
String argvalue = argdict->Get("value");
if (arginfo.IsObjectType<Dictionary>()) {
Dictionary::Ptr argdict = arginfo;
if (!MacroProcessor::ValidateMacroString(argvalue)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + argvalue + "'.", object->GetDebugInfo()));
if (argdict->Contains("value")) {
String argvalue = argdict->Get("value");
if (!MacroProcessor::ValidateMacroString(argvalue))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("arguments")(kv.first)("value"), "Validation failed: Closing $ not found in macro format string '" + argvalue + "'."));
}
}
if (argdict->Contains("set_if")) {
String argsetif = argdict->Get("set_if");
if (argdict->Contains("set_if")) {
String argsetif = argdict->Get("set_if");
if (!MacroProcessor::ValidateMacroString(argsetif)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + argsetif + "'.", object->GetDebugInfo()));
if (!MacroProcessor::ValidateMacroString(argsetif))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("arguments")(kv.first)("set_if"), "Closing $ not found in macro format string '" + argsetif + "'."));
}
}
} else if (arginfo.IsObjectType<Function>()) {
continue; /* we cannot evaluate macros in functions */
} else {
argval = arginfo;
} else if (arginfo.IsObjectType<Function>()) {
continue; /* we cannot evaluate macros in functions */
} else {
argval = arginfo;
if (argval.IsEmpty())
if (argval.IsEmpty())
continue;
String argstr = argval;
if (!MacroProcessor::ValidateMacroString(argstr))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("arguments")(kv.first), "Closing $ not found in macro format string '" + argstr + "'."));
}
}
}
Dictionary::Ptr env = GetEnv();
if (env) {
ObjectLock olock(env);
BOOST_FOREACH(const Dictionary::Pair& kv, env) {
const Value& envval = kv.second;
if (!envval.IsString() || envval.IsEmpty())
continue;
String argstr = argval;
if (!MacroProcessor::ValidateMacroString(argstr)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + argstr + "'.", object->GetDebugInfo()));
}
}
}
}
void Command::ValidateEnvironmentVariables(const String& location, const Command::Ptr& object)
{
Dictionary::Ptr env = object->GetEnv();
if (!env)
return;
ObjectLock olock(env);
BOOST_FOREACH(const Dictionary::Pair& kv, env) {
const Value& envval = kv.second;
if (!envval.IsString() || envval.IsEmpty())
continue;
if (!MacroProcessor::ValidateMacroString(envval)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + envval + "'.", object->GetDebugInfo()));
if (!MacroProcessor::ValidateMacroString(envval))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("env")(kv.first), "Closing $ not found in macro format string '" + envval + "'."));
}
}
}

View File

@ -39,9 +39,7 @@ public:
//virtual Dictionary::Ptr Execute(const Object::Ptr& context) = 0;
static void ValidateAttributes(const String& location, const Command::Ptr& object);
static void ValidateArguments(const String& location, const Command::Ptr& object);
static void ValidateEnvironmentVariables(const String& location, const Command::Ptr& object);
virtual void Validate(int types, const ValidationUtils& utils) override;
int GetModifiedAttributes(void) const;
void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin());

View File

@ -27,11 +27,41 @@ abstract class Command : CustomVarObject
{
[config] Value command (CommandLine);
[config] Value arguments;
[config] Value timeout {
[config] int timeout {
default {{{ return 60; }}}
};
[config] Dictionary::Ptr env;
[config] Function::Ptr execute;
[config, required] Function::Ptr execute;
};
validator Command {
String command;
Function command;
Array command {
String "*";
Function "*";
};
Dictionary arguments {
String "*";
Dictionary "*" {
String key;
String value;
Function value;
String description;
Number "required";
Number skip_key;
Number repeat_key;
String set_if;
Function set_if;
Number order;
};
};
Dictionary env {
String "*";
Function "*";
};
};
}

View File

@ -28,7 +28,6 @@
using namespace icinga;
REGISTER_TYPE(CustomVarObject);
REGISTER_SCRIPTFUNCTION(ValidateCustomAttributes, &CustomVarObject::ValidateCustomAttributes);
boost::signals2::signal<void (const CustomVarObject::Ptr&, const Dictionary::Ptr& vars, const MessageOrigin&)> CustomVarObject::OnVarsChanged;
@ -68,16 +67,14 @@ bool CustomVarObject::IsVarOverridden(const String& name) const
return vars_override->Contains(name);
}
void CustomVarObject::ValidateCustomAttributes(const String& location, const CustomVarObject::Ptr& object)
void CustomVarObject::ValidateVarsRaw(const Dictionary::Ptr& value, const ValidationUtils& utils)
{
Dictionary::Ptr vars = object->GetVars();
if (!vars)
if (!value)
return;
/* string, array, dictionary */
ObjectLock olock(vars);
BOOST_FOREACH(const Dictionary::Pair& kv, vars) {
ObjectLock olock(value);
BOOST_FOREACH(const Dictionary::Pair& kv, value) {
const Value& varval = kv.second;
if (varval.IsObjectType<Dictionary>()) {
@ -89,10 +86,8 @@ void CustomVarObject::ValidateCustomAttributes(const String& location, const Cus
if (kv_var.second.IsEmpty())
continue;
if (!MacroProcessor::ValidateMacroString(kv_var.second)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + kv_var.second + "'.", object->GetDebugInfo()));
}
if (!MacroProcessor::ValidateMacroString(kv_var.second))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("vars")(kv.first)(kv_var.first), "Closing $ not found in macro format string '" + kv_var.second + "'."));
}
} else if (varval.IsObjectType<Array>()) {
/* check all array entries */
@ -104,8 +99,7 @@ void CustomVarObject::ValidateCustomAttributes(const String& location, const Cus
continue;
if (!MacroProcessor::ValidateMacroString(arrval)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + arrval + "'.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("vars")(kv.first), "Closing $ not found in macro format string '" + arrval + "'."));
}
}
} else {
@ -114,10 +108,8 @@ void CustomVarObject::ValidateCustomAttributes(const String& location, const Cus
String varstr = varval;
if (!MacroProcessor::ValidateMacroString(varstr)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + varstr + "'.", object->GetDebugInfo()));
}
if (!MacroProcessor::ValidateMacroString(varstr))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of<String>("vars")(kv.first), "Closing $ not found in macro format string '" + varstr + "'."));
}
}
}

View File

@ -61,7 +61,7 @@ public:
static boost::signals2::signal<void (const CustomVarObject::Ptr&, const Dictionary::Ptr& vars, const MessageOrigin&)> OnVarsChanged;
static void ValidateCustomAttributes(const String& location, const CustomVarObject::Ptr& object);
virtual void ValidateVarsRaw(const Dictionary::Ptr& value, const ValidationUtils& utils) override;
Dictionary::Ptr GetVars(void) const;
void SetVars(const Dictionary::Ptr& vars, const MessageOrigin& origin = MessageOrigin());

View File

@ -20,14 +20,12 @@
#include "icinga/dependency.hpp"
#include "icinga/service.hpp"
#include "base/logger.hpp"
#include "base/function.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
REGISTER_TYPE(Dependency);
REGISTER_SCRIPTFUNCTION(ValidateDependencyFilters, &Dependency::ValidateFilters);
String DependencyNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const
{
@ -198,17 +196,15 @@ TimePeriod::Ptr Dependency::GetPeriod(void) const
return TimePeriod::GetByName(GetPeriodRaw());
}
void Dependency::ValidateFilters(const String& location, const Dependency::Ptr& object)
void Dependency::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils)
{
int sfilter = FilterArrayToInt(object->GetStates(), 0);
ObjectImpl<Dependency>::ValidateStates(value, utils);
if (object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid for host dependency.", object->GetDebugInfo()));
}
int sfilter = FilterArrayToInt(value, 0);
if (!object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid for service dependency.", object->GetDebugInfo()));
}
if (GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0)
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid for host dependency."));
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."));
}

View File

@ -51,7 +51,7 @@ public:
static void RegisterApplyRuleHandler(void);
static void ValidateFilters(const String& location, const Dependency::Ptr& object);
virtual void ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) override;
static void EvaluateApplyRules(const intrusive_ptr<Host>& host);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service);

View File

@ -36,13 +36,13 @@ class Dependency : CustomVarObject < DependencyNameComposer
load_after Host;
load_after Service;
[config] String child_host_name;
[config, required] name(Host) child_host_name;
[config] String child_service_name;
[config] String parent_host_name;
[config, required] name(Host) parent_host_name;
[config] String parent_service_name;
[config] String period (PeriodRaw);
[config] name(TimePeriod) period (PeriodRaw);
[config] Array::Ptr states;
int state_filter_real (StateFilter);
@ -57,4 +57,10 @@ class Dependency : CustomVarObject < DependencyNameComposer
};
};
validator Dependency {
Array states {
Number "*";
};
};
}

View File

@ -22,7 +22,6 @@
#include "icinga/hostgroup.hpp"
#include "icinga/pluginutility.hpp"
#include "icinga/scheduleddowntime.hpp"
#include "base/exception.hpp"
#include "base/objectlock.hpp"
#include "base/convert.hpp"
#include "base/utility.hpp"

View File

@ -49,4 +49,10 @@ class Host : Checkable
};
validator Host {
Array groups {
name(HostGroup) "*";
};
};
}

View File

@ -39,4 +39,10 @@ class HostGroup : CustomVarObject
[config] String action_url;
};
validator HostGroup {
Array groups {
name(HostGroup) "*";
};
};
}

View File

@ -1,293 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type IcingaApplication {
}
%type IcingaStatusWriter {
%attribute %string "status_path",
%attribute %number "update_interval"
}
%type CustomVarObject {
%validator "ValidateCustomAttributes",
%attribute %dictionary "vars",
}
%type Checkable %inherits CustomVarObject {
%validator "ValidateCheckableCheckInterval",
%attribute %string "display_name",
%require "check_command",
%attribute %name(CheckCommand) "check_command",
%attribute %number "max_check_attempts",
%attribute %name(TimePeriod) "check_period",
%attribute %number "check_interval",
%attribute %number "retry_interval",
%attribute %number "enable_notifications",
%attribute %number "enable_active_checks",
%attribute %number "enable_passive_checks",
%attribute %number "enable_event_handler",
%attribute %name(EventCommand) "event_command",
%attribute %number "enable_flapping",
%attribute %number "flapping_threshold",
%attribute %number "enable_perfdata",
%attribute %number "volatile",
%attribute %string "notes",
%attribute %string "notes_url",
%attribute %string "action_url",
%attribute %string "icon_image",
%attribute %string "icon_image_alt",
%attribute %name(Endpoint) "command_endpoint",
}
%type Host %inherits Checkable {
%attribute %string "display_name",
%attribute %array "groups" {
%attribute %name(HostGroup) "*"
},
%attribute %string "address",
%attribute %string "address6",
}
%type HostGroup %inherits CustomVarObject {
%attribute %string "display_name"
%attribute %array "groups" {
%attribute %name(HostGroup) "*"
},
%attribute %string "notes",
%attribute %string "notes_url",
%attribute %string "action_url",
}
%type Service %inherits Checkable {
%require "host_name",
%attribute %name(Host) "host_name",
%attribute %string "name",
%attribute %array "groups" {
%attribute %name(ServiceGroup) "*"
},
}
%type ServiceGroup %inherits CustomVarObject {
%attribute %string "display_name"
%attribute %array "groups" {
%attribute %name(ServiceGroup) "*"
},
%attribute %string "notes",
%attribute %string "notes_url",
%attribute %string "action_url",
}
%type Notification %inherits CustomVarObject {
%validator "ValidateNotificationFilters"
%validator "ValidateNotificationUsers"
%require "host_name",
%attribute %name(Host) "host_name",
%attribute %string "service_name",
%attribute %string "name",
%attribute %array "users" {
%attribute %name(User) "*"
},
%attribute %array "user_groups" {
%attribute %name(UserGroup) "*"
},
%attribute %dictionary "times" {
%attribute %number "begin",
%attribute %number "end",
},
%require "command",
%attribute %name(NotificationCommand) "command",
%attribute %number "interval",
%attribute %name(TimePeriod) "period",
%attribute %array "types" {
%attribute %number "*"
},
%attribute %array "states" {
%attribute %number "*"
},
%attribute %name(Endpoint) "command_endpoint",
}
%type User %inherits CustomVarObject {
%validator "ValidateUserFilters"
%attribute %string "display_name",
%attribute %array "groups" {
%attribute %name(UserGroup) "*"
},
%attribute %number "enable_notifications",
%attribute %array "types" {
%attribute %number "*"
},
%attribute %array "states" {
%attribute %number "*"
},
%attribute %name(TimePeriod) "period",
%attribute %string "email",
%attribute %string "pager",
}
%type UserGroup %inherits CustomVarObject {
%attribute %string "display_name",
%attribute %array "groups" {
%attribute %name(UserGroup) "*"
},
}
%type TimePeriod %inherits CustomVarObject {
%validator "ValidateTimePeriodRanges",
%attribute %string "display_name",
%require "update",
%attribute %function "update",
/* %if (methods.update == "LegacyTimePeriod") { */
// %require "ranges",
%attribute %dictionary "ranges" {
%attribute %string "*"
}
/* } */
}
%type Command %inherits CustomVarObject {
%validator "ValidateCommandAttributes",
%validator "ValidateCommandArguments",
%validator "ValidateEnvironmentVariables",
%require "execute",
%attribute %function "execute",
/* %if (methods.execute == "PluginNotification" || methods.execute == "PluginCheck" || methods.execute == "PluginEvent") { */
// %require "command",
%attribute %string "command",
%attribute %function "command",
%attribute %array "command" {
%attribute %string "*"
%attribute %function "*",
},
%attribute %dictionary "arguments" {
%attribute %string "*",
%attribute %dictionary "*" {
%attribute %string "key"
%attribute %string "value"
%attribute %function "value"
%attribute %string "description"
%attribute %number "required"
%attribute %number "skip_key"
%attribute %number "repeat_key"
%attribute %string "set_if"
%attribute %function "set_if"
%attribute %number "order"
}
},
%attribute %dictionary "env" {
%attribute %string "*"
%attribute %function "*"
},
%attribute %number "timeout"
/* } */
}
%type CheckCommand %inherits Command {
}
%type NotificationCommand %inherits Command {
}
%type EventCommand %inherits Command {
}
%type ScheduledDowntime %inherits CustomVarObject {
%validator "ValidateScheduledDowntimeRanges",
%require "host_name",
%attribute %name(Host) "host_name",
%attribute %string "service_name",
%attribute %string "name",
%require "author",
%attribute %string "author",
%require "comment",
%attribute %string "comment",
%attribute %number "duration",
%attribute %number "fixed",
%require "ranges",
%attribute %dictionary "ranges" {
%attribute %string "*"
},
}
%type Dependency %inherits CustomVarObject {
%validator "ValidateDependencyFilters"
%require "parent_host_name",
%attribute %name(Host) "parent_host_name",
%attribute %string "parent_service_name",
%require "child_host_name",
%attribute %name(Host) "child_host_name",
%attribute %string "child_service_name",
%attribute %string "name",
%attribute %name(TimePeriod) "period",
%attribute %array "states" {
%attribute %number "*"
},
%attribute %number "ignore_soft_states",
%attribute %number "disable_checks",
%attribute %number "disable_notifications"
}

View File

@ -27,14 +27,11 @@
#include "base/exception.hpp"
#include "base/initialize.hpp"
#include "base/scriptglobal.hpp"
#include "base/function.hpp"
#include <boost/foreach.hpp>
using namespace icinga;
REGISTER_TYPE(Notification);
REGISTER_SCRIPTFUNCTION(ValidateNotificationFilters, &Notification::ValidateFilters);
REGISTER_SCRIPTFUNCTION(ValidateNotificationUsers, &Notification::ValidateUsers);
INITIALIZE_ONCE(&Notification::StaticInitialize);
boost::signals2::signal<void (const Notification::Ptr&, double, const MessageOrigin&)> Notification::OnNextNotificationChanged;
@ -256,8 +253,8 @@ void Notification::BeginExecuteNotification(NotificationType type, const CheckRe
<< "Not sending notifications for notification object '" << GetName() << "': before escalation range";
/* we need to adjust the next notification time
* to now + begin delaying the first notification
*/
* to now + begin delaying the first notification
*/
double nextProposedNotification = now + times->Get("begin") + 1.0;
if (GetNextNotification() > nextProposedNotification)
SetNextNotification(nextProposedNotification);
@ -628,43 +625,46 @@ String Notification::NotificationHostStateToString(HostState state)
}
}
void Notification::ValidateUsers(const String& location, const Notification::Ptr& object)
void Notification::Validate(int types, const ValidationUtils& utils)
{
Array::Ptr users = object->GetUsersRaw();
Array::Ptr groups = object->GetUserGroupsRaw();
ObjectImpl<Notification>::Validate(types, utils);
if ((!users || users->GetLength() == 0) && (!groups || groups->GetLength() == 0)) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": No users/user_groups specified.", object->GetDebugInfo()));
}
if (!(types & FAConfig))
return;
Array::Ptr users = GetUsersRaw();
Array::Ptr groups = GetUserGroupsRaw();
if ((!users || users->GetLength() == 0) && (!groups || groups->GetLength() == 0))
BOOST_THROW_EXCEPTION(ValidationError(this, std::vector<String>(), "Validation failed: No users/user_groups specified."));
}
void Notification::ValidateFilters(const String& location, const Notification::Ptr& object)
void Notification::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils)
{
int sfilter = FilterArrayToInt(object->GetStates(), 0);
ObjectImpl<Notification>::ValidateStates(value, utils);
if (object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid.", object->GetDebugInfo()));
}
int sfilter = FilterArrayToInt(value, 0);
if (!object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid.", object->GetDebugInfo()));
}
if (GetServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0)
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid."));
int tfilter = FilterArrayToInt(object->GetTypes(), 0);
if (!GetServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0)
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("types"), "State filter is invalid."));
}
void Notification::ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils)
{
ObjectImpl<Notification>::ValidateTypes(value, utils);
int tfilter = FilterArrayToInt(value, 0);
if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery |
1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Type filter is invalid.", object->GetDebugInfo()));
}
1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0)
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("types"), "Type filter is invalid."));
}
Endpoint::Ptr Notification::GetCommandEndpoint(void) const
{
return Endpoint::GetByName(GetCommandEndpointRaw());
}

View File

@ -110,8 +110,10 @@ public:
static void RegisterApplyRuleHandler(void);
static void ValidateUsers(const String& location, const Notification::Ptr& object);
static void ValidateFilters(const String& location, const Notification::Ptr& object);
virtual void Validate(int types, const ValidationUtils& utils) override;
virtual void ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) override;
virtual void ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils) override;
static void EvaluateApplyRules(const intrusive_ptr<Host>& host);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service);

View File

@ -35,11 +35,11 @@ class Notification : CustomVarObject < NotificationNameComposer
load_after Host;
load_after Service;
[config, protected] String command (CommandRaw);
[config, protected, required] name(NotificationCommand) command (CommandRaw);
[config] double interval {
default {{{ return 1800; }}}
};
[config] String period (PeriodRaw);
[config] name(TimePeriod) period (PeriodRaw);
[config, protected] Array::Ptr users (UsersRaw);
[config, protected] Array::Ptr user_groups (UserGroupsRaw);
[config] Dictionary::Ptr times;
@ -47,7 +47,7 @@ class Notification : CustomVarObject < NotificationNameComposer
int type_filter_real (TypeFilter);
[config] Array::Ptr states;
int state_filter_real (StateFilter);
[config, protected] String host_name;
[config, protected, required] name(Host) host_name;
[config, protected] String service_name;
[state] Array::Ptr notified_users {
@ -59,7 +59,30 @@ class Notification : CustomVarObject < NotificationNameComposer
[state, set_protected] Value notification_number;
[state] double last_problem_notification;
[config] String command_endpoint (CommandEndpointRaw);
[config] name(Endpoint) command_endpoint (CommandEndpointRaw);
};
validator Notification {
Array users {
name(User) "*";
};
Array user_groups {
name(UserGroup) "*";
};
Dictionary times {
Number begin;
Number end;
};
Array types {
Number "*";
};
Array states {
Number "*";
};
};
}

View File

@ -34,7 +34,6 @@
using namespace icinga;
REGISTER_TYPE(ScheduledDowntime);
REGISTER_SCRIPTFUNCTION(ValidateScheduledDowntimeRanges, &ScheduledDowntime::ValidateRanges);
INITIALIZE_ONCE(&ScheduledDowntime::StaticInitialize);
@ -181,11 +180,9 @@ void ScheduledDowntime::CreateNextDowntime(void)
downtime->SetConfigOwner(GetName());
}
void ScheduledDowntime::ValidateRanges(const String& location, const ScheduledDowntime::Ptr& object)
void ScheduledDowntime::ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils)
{
Dictionary::Ptr ranges = object->GetRanges();
if (!ranges)
if (!value)
return;
/* create a fake time environment to validate the definitions */
@ -193,22 +190,20 @@ void ScheduledDowntime::ValidateRanges(const String& location, const ScheduledDo
tm reference = Utility::LocalTime(refts);
Array::Ptr segments = new Array();
ObjectLock olock(ranges);
BOOST_FOREACH(const Dictionary::Pair& kv, ranges) {
ObjectLock olock(value);
BOOST_FOREACH(const Dictionary::Pair& kv, value) {
try {
tm begin_tm, end_tm;
int stride;
LegacyTimePeriod::ParseTimeRange(kv.first, &begin_tm, &end_tm, &stride, &reference);
} catch (std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Invalid time specification.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time specification: " + kv.first));
}
try {
LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments);
} catch (std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Invalid time range definition.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time range definition: " + kv.first));
}
}
}

View File

@ -53,7 +53,7 @@ public:
static void EvaluateApplyRules(const intrusive_ptr<Host>& host);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service);
static void ValidateRanges(const String& location, const ScheduledDowntime::Ptr& object);
virtual void ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils) override;
protected:
virtual void OnAllConfigLoaded(void);

View File

@ -35,18 +35,24 @@ class ScheduledDowntime : CustomVarObject < ScheduledDowntimeNameComposer
load_after Host;
load_after Service;
[config, protected] String host_name;
[config, protected, required] name(Host) host_name;
[config, protected] String service_name;
[config] String author;
[config] String comment;
[config, required] String author;
[config, required] String comment;
[config] double duration;
[config] bool fixed {
default {{{ return true; }}}
};
[config] Dictionary::Ptr ranges;
[config, required] Dictionary::Ptr ranges;
};
validator ScheduledDowntime {
Dictionary ranges {
String "*";
};
};
}

View File

@ -45,7 +45,7 @@ class Service : Checkable < ServiceNameComposer
return m_DisplayName;
}}}
};
[config] String host_name;
[config, required] name(Host) host_name;
[enum, no_storage] ServiceState "state" {
get {{{
return GetStateRaw();
@ -63,4 +63,10 @@ class Service : Checkable < ServiceNameComposer
};
};
validator Service {
Array groups {
name(ServiceGroup) "*";
};
};
}

View File

@ -39,4 +39,10 @@ class ServiceGroup : CustomVarObject
[config] String action_url;
};
validator ServiceGroup {
Array groups {
name(ServiceGroup) "*";
};
};
}

View File

@ -30,7 +30,6 @@
using namespace icinga;
REGISTER_TYPE(TimePeriod);
REGISTER_SCRIPTFUNCTION(ValidateTimePeriodRanges, &TimePeriod::ValidateRanges);
static Timer::Ptr l_UpdateTimer;
@ -306,11 +305,9 @@ void TimePeriod::Dump(void)
Log(LogDebug, "TimePeriod", "---");
}
void TimePeriod::ValidateRanges(const String& location, const TimePeriod::Ptr& object)
void TimePeriod::ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils)
{
Dictionary::Ptr ranges = object->GetRanges();
if (!ranges)
if (!value)
return;
/* create a fake time environment to validate the definitions */
@ -318,22 +315,20 @@ void TimePeriod::ValidateRanges(const String& location, const TimePeriod::Ptr& o
tm reference = Utility::LocalTime(refts);
Array::Ptr segments = new Array();
ObjectLock olock(ranges);
BOOST_FOREACH(const Dictionary::Pair& kv, ranges) {
ObjectLock olock(value);
BOOST_FOREACH(const Dictionary::Pair& kv, value) {
try {
tm begin_tm, end_tm;
int stride;
LegacyTimePeriod::ParseTimeRange(kv.first, &begin_tm, &end_tm, &stride, &reference);
} catch (std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Invalid time specification.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time specification: " + kv.first));
}
try {
LegacyTimePeriod::ProcessTimeRanges(kv.second, &reference, segments);
} catch (std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Invalid time range definition.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("ranges"), "Invalid time range definition: " + kv.second));
}
}
}

View File

@ -48,7 +48,7 @@ public:
bool IsInside(double ts) const;
double FindNextTransition(double begin);
static void ValidateRanges(const String& location, const TimePeriod::Ptr& object);
virtual void ValidateRanges(const Dictionary::Ptr& value, const ValidationUtils& utils) override;
private:
void AddSegment(double s, double end);

View File

@ -34,7 +34,7 @@ class TimePeriod : CustomVarObject
}}}
};
[config] Dictionary::Ptr ranges;
[config] Function::Ptr update;
[config, required] Function::Ptr update;
[state] Value valid_begin;
[state] Value valid_end;
[state] Array::Ptr segments;
@ -43,4 +43,10 @@ class TimePeriod : CustomVarObject
};
};
validator TimePeriod {
Dictionary ranges {
String "*";
};
};
}

View File

@ -21,7 +21,6 @@
#include "icinga/usergroup.hpp"
#include "icinga/notification.hpp"
#include "icinga/usergroup.hpp"
#include "base/function.hpp"
#include "base/objectlock.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
@ -29,7 +28,6 @@
using namespace icinga;
REGISTER_TYPE(User);
REGISTER_SCRIPTFUNCTION(ValidateUserFilters, &User::ValidateFilters);
boost::signals2::signal<void (const User::Ptr&, bool, const MessageOrigin&)> User::OnEnableNotificationsChanged;
@ -101,22 +99,25 @@ TimePeriod::Ptr User::GetPeriod(void) const
return TimePeriod::GetByName(GetPeriodRaw());
}
void User::ValidateFilters(const String& location, const User::Ptr& object)
void User::ValidateStates(const Array::Ptr& value, const ValidationUtils& utils)
{
int sfilter = FilterArrayToInt(object->GetStates(), 0);
ObjectImpl<User>::ValidateStates(value, utils);
int sfilter = FilterArrayToInt(value, 0);
if ((sfilter & ~(StateFilterUp | StateFilterDown | StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("states"), "State filter is invalid."));
}
}
int tfilter = FilterArrayToInt(object->GetTypes(), 0);
void User::ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils)
{
int tfilter = FilterArrayToInt(value, 0);
if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery |
1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Type filter is invalid.", object->GetDebugInfo()));
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("types"), "Type filter is invalid."));
}
}

View File

@ -44,7 +44,8 @@ public:
/* Notifications */
TimePeriod::Ptr GetPeriod(void) const;
static void ValidateFilters(const String& location, const User::Ptr& attrs);
virtual void ValidateStates(const Array::Ptr& value, const ValidationUtils& utils) override;
virtual void ValidateTypes(const Array::Ptr& value, const ValidationUtils& utils) override;
bool GetEnableNotifications(void) const;
void SetEnableNotifications(bool enabled, const MessageOrigin& origin = MessageOrigin());

View File

@ -36,7 +36,7 @@ class User : CustomVarObject
[config] Array::Ptr groups {
default {{{ return new Array(); }}}
};
[config] String period (PeriodRaw);
[config] name(TimePeriod) period (PeriodRaw);
[config] Array::Ptr types;
int type_filter_real (TypeFilter);
[config] Array::Ptr states;
@ -53,4 +53,18 @@ class User : CustomVarObject
[state] double last_notification;
};
validator User {
Array groups {
name(UserGroup) "*";
};
Array types {
Number "*";
};
Array states {
Number "*";
};
};
}

View File

@ -36,4 +36,10 @@ class UserGroup : CustomVarObject
[config] Array::Ptr groups;
};
validator UserGroup {
Array groups {
name(UserGroup) "*";
};
};
}

View File

@ -17,8 +17,6 @@
mkclass_target(livestatuslistener.ti livestatuslistener.thpp)
mkembedconfig_target(livestatus-type.conf livestatus-type.cpp)
set(livestatus_SOURCES
aggregator.cpp andfilter.cpp attributefilter.cpp
avgaggregator.cpp column.cpp combinerfilter.cpp commandstable.cpp
@ -30,7 +28,7 @@ set(livestatus_SOURCES
minaggregator.cpp negatefilter.cpp orfilter.cpp
servicegroupstable.cpp servicestable.cpp statehisttable.cpp
statustable.cpp stdaggregator.cpp sumaggregator.cpp table.cpp
timeperiodstable.cpp livestatus-type.cpp
timeperiodstable.cpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,30 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type LivestatusListener {
%validator "ValidateSocketType",
%attribute %string "socket_type",
%attribute %string "socket_path",
%attribute %string "bind_host",
%attribute %string "bind_port",
%attribute %string "compat_log_path",
}

View File

@ -35,7 +35,6 @@
using namespace icinga;
REGISTER_TYPE(LivestatusListener);
REGISTER_SCRIPTFUNCTION(ValidateSocketType, &LivestatusListener::ValidateSocketType);
static int l_ClientsConnected = 0;
static int l_Connections = 0;
@ -213,12 +212,10 @@ void LivestatusListener::ClientHandler(const Socket::Ptr& client)
}
void LivestatusListener::ValidateSocketType(const String& location, const LivestatusListener::Ptr& object)
void LivestatusListener::ValidateSocketType(const String& value, const ValidationUtils& utils)
{
String socket_type = object->GetSocketType();
ObjectImpl<LivestatusListener>::ValidateSocketType(value, utils);
if (socket_type != "unix" && socket_type != "tcp") {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Socket type '" + socket_type + "' is invalid.", object->GetDebugInfo()));
}
if (value != "unix" && value != "tcp")
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("socket_type"), "Socket type '" + value + "' is invalid."));
}

View File

@ -45,7 +45,7 @@ public:
static int GetClientsConnected(void);
static int GetConnections(void);
static void ValidateSocketType(const String& location, const LivestatusListener::Ptr& object);
virtual void ValidateSocketType(const String& value, const ValidationUtils& utils) override;
protected:
virtual void Start(void);

View File

@ -17,10 +17,8 @@
mkclass_target(notificationcomponent.ti notificationcomponent.thpp)
mkembedconfig_target(notification-type.conf notification-type.cpp)
set(notification_SOURCES
notificationcomponent.cpp notificationcomponent.thpp notification-type.cpp
notificationcomponent.cpp notificationcomponent.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -1,22 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type NotificationComponent {
%attribute %number "enable_ha"
}

View File

@ -20,10 +20,8 @@ mkclass_target(graphitewriter.ti graphitewriter.thpp)
mkclass_target(opentsdbwriter.ti opentsdbwriter.thpp)
mkclass_target(perfdatawriter.ti perfdatawriter.thpp)
mkembedconfig_target(perfdata-type.conf perfdata-type.cpp)
set(perfdata_SOURCES
gelfwriter.cpp gelfwriter.thpp graphitewriter.cpp graphitewriter.thpp opentsdbwriter.cpp opentsdbwriter.thpp perfdatawriter.cpp perfdatawriter.thpp perfdata-type.cpp
gelfwriter.cpp gelfwriter.thpp graphitewriter.cpp graphitewriter.thpp opentsdbwriter.cpp opentsdbwriter.thpp perfdatawriter.cpp perfdatawriter.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -43,7 +43,6 @@
using namespace icinga;
REGISTER_TYPE(GraphiteWriter);
REGISTER_SCRIPTFUNCTION(ValidateNameTemplates, &GraphiteWriter::ValidateNameTemplates);
REGISTER_STATSFUNCTION(GraphiteWriterStats, &GraphiteWriter::StatsFunc);
@ -232,15 +231,18 @@ Value GraphiteWriter::EscapeMacroMetric(const Value& value)
return EscapeMetric(value);
}
void GraphiteWriter::ValidateNameTemplates(const String& location, const GraphiteWriter::Ptr& object)
void GraphiteWriter::ValidateHostNameTemplate(const String& value, const ValidationUtils& utils)
{
if (!MacroProcessor::ValidateMacroString(object->GetHostNameTemplate())) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + object->GetHostNameTemplate() + "'.", object->GetDebugInfo()));
}
ObjectImpl<GraphiteWriter>::ValidateHostNameTemplate(value, utils);
if (!MacroProcessor::ValidateMacroString(object->GetServiceNameTemplate())) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + object->GetServiceNameTemplate() + "'.", object->GetDebugInfo()));
}
if (!MacroProcessor::ValidateMacroString(value))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("host_name_template"), "Closing $ not found in macro format string '" + value + "'."));
}
void GraphiteWriter::ValidateServiceNameTemplate(const String& value, const ValidationUtils& utils)
{
ObjectImpl<GraphiteWriter>::ValidateServiceNameTemplate(value, utils);
if (!MacroProcessor::ValidateMacroString(value))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("service_name_template"), "Closing $ not found in macro format string '" + value + "'."));
}

View File

@ -43,7 +43,8 @@ public:
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
static void ValidateNameTemplates(const String& location, const GraphiteWriter::Ptr& object);
virtual void ValidateHostNameTemplate(const String& value, const ValidationUtils& utils) override;
virtual void ValidateServiceNameTemplate(const String& value, const ValidationUtils& utils) override;
protected:
virtual void Start(void);

View File

@ -1,50 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type PerfdataWriter {
%validator "ValidateFormatTemplates",
%attribute %string "host_perfdata_path",
%attribute %string "service_perfdata_path",
%attribute %string "host_temp_path",
%attribute %string "service_temp_path",
%attribute %string "host_format_template",
%attribute %string "service_format_template",
%attribute %number "rotation_interval"
}
%type GraphiteWriter {
%validator "ValidateNameTemplates",
%attribute %string "host",
%attribute %string "port",
%attribute %string "host_name_template",
%attribute %string "service_name_template"
}
%type GelfWriter {
%attribute %string "host",
%attribute %string "port",
%attribute %string "source"
}
%type OpenTsdbWriter {
%attribute %string "host",
%attribute %string "port",
}

View File

@ -34,7 +34,6 @@
using namespace icinga;
REGISTER_TYPE(PerfdataWriter);
REGISTER_SCRIPTFUNCTION(ValidateFormatTemplates, &PerfdataWriter::ValidateFormatTemplates);
REGISTER_STATSFUNCTION(PerfdataWriterStats, &PerfdataWriter::StatsFunc);
@ -140,15 +139,18 @@ void PerfdataWriter::RotationTimerHandler(void)
RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
}
void PerfdataWriter::ValidateFormatTemplates(const String& location, const PerfdataWriter::Ptr& object)
void PerfdataWriter::ValidateHostFormatTemplate(const String& value, const ValidationUtils& utils)
{
if (!MacroProcessor::ValidateMacroString(object->GetHostFormatTemplate())) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + object->GetHostFormatTemplate() + "'.", object->GetDebugInfo()));
}
ObjectImpl<PerfdataWriter>::ValidateHostFormatTemplate(value, utils);
if (!MacroProcessor::ValidateMacroString(object->GetServiceFormatTemplate())) {
BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Closing $ not found in macro format string '" + object->GetHostFormatTemplate() + "'.", object->GetDebugInfo()));
}
if (!MacroProcessor::ValidateMacroString(value))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("host_format_template"), "Closing $ not found in macro format string '" + value + "'."));
}
void PerfdataWriter::ValidateServiceFormatTemplate(const String& value, const ValidationUtils& utils)
{
ObjectImpl<PerfdataWriter>::ValidateServiceFormatTemplate(value, utils);
if (!MacroProcessor::ValidateMacroString(value))
BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("service_format_template"), "Closing $ not found in macro format string '" + value + "'."));
}

View File

@ -42,7 +42,8 @@ public:
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
static void ValidateFormatTemplates(const String& location, const PerfdataWriter::Ptr& object);
virtual void ValidateHostFormatTemplate(const String& value, const ValidationUtils& utils) override;
virtual void ValidateServiceFormatTemplate(const String& value, const ValidationUtils& utils) override;
protected:
virtual void Start(void);

View File

@ -19,12 +19,10 @@ mkclass_target(apilistener.ti apilistener.thpp)
mkclass_target(endpoint.ti endpoint.thpp)
mkclass_target(zone.ti zone.thpp)
mkembedconfig_target(remote-type.conf remote-type.cpp)
set(remote_SOURCES
apiclient.cpp apiclient-heartbeat.cpp apifunction.cpp apilistener.cpp apilistener-sync.cpp
apilistener.thpp authority.cpp endpoint.cpp endpoint.thpp jsonrpc.cpp
messageorigin.cpp remote-type.cpp zone.cpp zone.thpp
messageorigin.cpp zone.cpp zone.thpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -25,9 +25,9 @@ namespace icinga
class ApiListener : DynamicObject
{
[config] String cert_path;
[config] String key_path;
[config] String ca_path;
[config, required] String cert_path;
[config, required] String key_path;
[config, required] String ca_path;
[config] String crl_path;
[config] String bind_host;

View File

@ -1,56 +0,0 @@
/******************************************************************************
* 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. *
******************************************************************************/
%type ApiListener {
%require "cert_path",
%attribute %string "cert_path",
%require "key_path",
%attribute %string "key_path",
%require "ca_path",
%attribute %string "ca_path",
%attribute %string "crl_path",
%attribute %string "bind_host",
%attribute %string "bind_port",
%attribute %number "accept_config",
%attribute %number "accept_commands",
%attribute %string "ticket_salt"
}
%type Endpoint {
%attribute %string "host",
%attribute %string "port",
%attribute %number "log_duration"
}
%type Zone {
%attribute %name(Zone) "parent",
%attribute %array "endpoints" {
%attribute %name(Endpoint) "*"
},
%attribute %number "global"
}

View File

@ -24,9 +24,15 @@ namespace icinga
class Zone : DynamicObject
{
[config] String parent (ParentRaw);
[config] name(Zone) parent (ParentRaw);
[config] Array::Ptr endpoints (EndpointsRaw);
[config] bool global;
};
validator Zone {
Array endpoints {
name(Endpoint) "*";
};
};
}

View File

@ -18,6 +18,7 @@
******************************************************************************/
#include "config/configcompiler.hpp"
#include "base/exception.hpp"
#include <boost/test/unit_test.hpp>
using namespace icinga;

View File

@ -18,13 +18,9 @@
******************************************************************************/
#include "livestatus/livestatusquery.hpp"
#include "config/configtype.hpp"
#include "config/configcompiler.hpp"
#include "config/configitem.hpp"
#include "base/application.hpp"
#include "base/debug.hpp"
#include "base/objectlock.hpp"
#include "base/console.hpp"
#include "base/serializer.hpp"
#include "base/stdiostream.hpp"
#include "base/json.hpp"
#include "base/loader.hpp"
@ -32,7 +28,6 @@
#include <boost/test/unit_test.hpp>
#include <fstream>
using namespace icinga;
struct GlobalConfigFixture {

View File

@ -143,6 +143,9 @@ set_protected { yylval->num = FASetProtected; return T_FIELD_ATTRIBUTE; }
protected { yylval->num = FAGetProtected | FASetProtected; return T_FIELD_ATTRIBUTE; }
internal { yylval->num = FAInternal; return T_FIELD_ATTRIBUTE; }
no_storage { yylval->num = FANoStorage; return T_FIELD_ATTRIBUTE; }
validator { return T_VALIDATOR; }
required { return T_REQUIRED; }
name { return T_NAME; }
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; }

View File

@ -45,11 +45,15 @@ using namespace icinga;
%union {
char *text;
int num;
FieldType *type;
Field *field;
std::vector<Field> *fields;
Klass *klass;
FieldAccessor *fieldaccessor;
std::vector<FieldAccessor> *fieldaccessors;
Rule *rule;
std::vector<Rule> *rules;
Validator *validator;
}
%token T_INCLUDE "include (T_INCLUDE)"
@ -57,6 +61,9 @@ using namespace icinga;
%token T_CODE "code (T_CODE)"
%token T_LOAD_AFTER "load_after (T_LOAD_AFTER)"
%token T_NAMESPACE "namespace (T_NAMESPACE)"
%token T_VALIDATOR "validator (T_VALIDATOR)"
%token T_REQUIRED "required (T_REQUIRED)"
%token T_NAME "name (T_NAME)"
%token T_STRING "string (T_STRING)"
%token T_ANGLE_STRING "angle_string (T_ANGLE_STRING)"
%token T_FIELD_ATTRIBUTE "field_attribute (T_FIELD_ATTRIBUTE)"
@ -77,17 +84,22 @@ using namespace icinga;
%type <text> angle_include
%type <text> code
%type <num> T_FIELD_ATTRIBUTE
%type <num> field_attribute
%type <num> field_attributes
%type <num> field_attribute_list
%type <num> T_FIELD_ACCESSOR_TYPE
%type <num> T_CLASS_ATTRIBUTE
%type <num> class_attribute_list
%type <type> field_type
%type <field> class_field
%type <fields> class_fields
%type <klass> class
%type <fieldaccessors> field_accessor_list
%type <fieldaccessors> field_accessors
%type <fieldaccessor> field_accessor
%type <rule> validator_rule
%type <rules> validator_rules
%type <validator> validator
%{
@ -110,6 +122,8 @@ void ClassCompiler::Compile(void)
} catch (const std::exception& ex) {
std::cerr << "Exception: " << ex.what();
}
HandleMissingValidators();
}
#define scanner (context->GetScanner())
@ -137,6 +151,11 @@ statement: include
context->HandleClass(*$1, yylloc);
delete $1;
}
| validator
{
context->HandleValidator(*$1, yylloc);
delete $1;
}
| namespace
| code
{
@ -250,7 +269,23 @@ class_fields: /* empty */
}
;
class_field: field_attribute_list identifier identifier alternative_name_specifier field_accessor_list ';'
field_type: identifier
{
$$ = new FieldType();
$$->IsName = false;
$$->TypeName = $1;
free($1);
}
| T_NAME '(' identifier ')'
{
$$ = new FieldType();
$$->IsName = true;
$$->TypeName = $3;
free($3);
}
;
class_field: field_attribute_list field_type identifier alternative_name_specifier field_accessor_list ';'
{
Field *field = new Field();
@ -259,8 +294,8 @@ class_field: field_attribute_list identifier identifier alternative_name_specifi
if ((field->Attributes & (FAConfig | FAState)) == 0)
field->Attributes |= FAEphemeral;
field->Type = $2;
std::free($2);
field->Type = *$2;
delete $2;
field->Name = $3;
std::free($3);
@ -321,15 +356,25 @@ field_attribute_list: /* empty */
}
;
field_attribute: T_FIELD_ATTRIBUTE
{
$$ = $1;
}
| T_REQUIRED
{
$$ = FARequired;
}
;
field_attributes: /* empty */
{
$$ = 0;
}
| field_attributes ',' T_FIELD_ATTRIBUTE
| field_attributes ',' field_attribute
{
$$ = $1 | $3;
}
| T_FIELD_ATTRIBUTE
| field_attribute
{
$$ = $1;
}
@ -368,6 +413,84 @@ field_accessor: T_FIELD_ACCESSOR_TYPE T_STRING
}
;
validator_rules: /* empty */
{
$$ = new std::vector<Rule>();
}
| validator_rules validator_rule
{
$$->push_back(*$2);
delete $2;
}
;
validator_rule: T_NAME '(' T_IDENTIFIER ')' identifier ';'
{
$$ = new Rule();
$$->Attributes = 0;
$$->IsName = true;
$$->Type = $3;
std::free($3);
$$->Pattern = $5;
std::free($5);
}
| T_IDENTIFIER identifier ';'
{
$$ = new Rule();
$$->Attributes = 0;
$$->IsName = false;
$$->Type = $1;
std::free($1);
$$->Pattern = $2;
std::free($2);
}
| T_NAME '(' T_IDENTIFIER ')' identifier '{' validator_rules '}' ';'
{
$$ = new Rule();
$$->Attributes = 0;
$$->IsName = true;
$$->Type = $3;
std::free($3);
$$->Pattern = $5;
std::free($5);
$$->Rules = *$7;
delete $7;
}
| T_IDENTIFIER identifier '{' validator_rules '}' ';'
{
$$ = new Rule();
$$->Attributes = 0;
$$->IsName = false;
$$->Type = $1;
std::free($1);
$$->Pattern = $2;
std::free($2);
$$->Rules = *$4;
delete $4;
}
| T_REQUIRED identifier ';'
{
$$ = new Rule();
$$->Attributes = RARequired;
$$->IsName = false;
$$->Type = "";
$$->Pattern = $2;
std::free($2);
}
;
validator: T_VALIDATOR T_IDENTIFIER '{' validator_rules '}' ';'
{
$$ = new Validator();
$$->Name = $2;
std::free($2);
$$->Rules = *$4;
delete $4;
}
;
identifier: T_IDENTIFIER
| T_STRING
{

View File

@ -19,9 +19,11 @@
#include "classcompiler.hpp"
#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#ifndef _WIN32
@ -77,6 +79,8 @@ void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDeb
void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo&)
{
HandleMissingValidators();
std::cout << "}" << std::endl;
}
@ -94,16 +98,16 @@ unsigned long ClassCompiler::SDBM(const std::string& str, size_t len = std::stri
for (it = str.begin(); it != str.end(); it++) {
if (current >= len)
break;
break;
char c = *it;
hash = c + (hash << 6) + (hash << 16) - hash;
hash = c + (hash << 6) + (hash << 16) - hash;
current++;
}
current++;
}
return hash;
return hash;
}
static int TypePreference(const std::string& type)
@ -124,12 +128,12 @@ static int TypePreference(const std::string& type)
static bool FieldLayoutCmp(const Field& a, const Field& b)
{
return TypePreference(a.Type) < TypePreference(b.Type);
return TypePreference(a.Type.GetRealType()) < TypePreference(b.Type.GetRealType());
}
static bool FieldTypeCmp(const Field& a, const Field& b)
{
return a.Type < b.Type;
return a.Type.GetRealType() < b.Type.GetRealType();
}
void ClassCompiler::OptimizeStructLayout(std::vector<Field>& fields)
@ -297,7 +301,10 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
size_t num = 0;
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
std::string ftype = it->Type;
std::string ftype = it->Type.GetRealType();
if (ftype == "bool" || ftype == "int" || ftype == "double")
ftype = "Number";
if (ftype == "int" || ftype == "double")
ftype = "Number";
@ -310,8 +317,15 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
if (it->Attributes & FAEnum)
ftype = "Number";
std::string nameref;
if (it->Type.IsName)
nameref = "\"" + it->Type.TypeName + "\"";
else
nameref = "NULL";
std::cout << "\t\t\t" << "case " << num << ":" << std::endl
<< "\t\t\t\t" << "return Field(" << num << ", \"" << ftype << "\", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
<< "\t\t\t\t" << "return Field(" << num << ", \"" << ftype << "\", \"" << it->Name << "\", " << nameref << ", " << it->Attributes << ");" << std::endl;
num++;
}
@ -362,13 +376,56 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
std::cout << "};" << std::endl << std::endl;
std::cout << std::endl;
/* ObjectImpl */
std::cout << "template<>" << std::endl
<< "class ObjectImpl<" << klass.Name << ">"
<< " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
<< "{" << std::endl
<< "public:" << std::endl
<< "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl;
<< "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
/* Validate */
std::cout << "\t" << "virtual void Validate(int types, const ValidationUtils& utils)" << std::endl
<< "\t" << "{" << std::endl;
if (!klass.Parent.empty())
std::cout << "\t\t" << klass.Parent << "::Validate(types, utils);" << std::endl << std::endl;
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
std::cout << "\t\t" << "if (" << (it->Attributes & (FAEphemeral|FAConfig|FAState)) << " & types)" << std::endl
<< "\t\t\t" << "Validate" << it->GetFriendlyName() << "(Get" << it->GetFriendlyName() << "(), utils);" << std::endl;
}
std::cout << "\t" << "}" << std::endl << std::endl;
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
std::cout << "\t" << "inline void SimpleValidate" << it->GetFriendlyName() << "(" << it->Type.GetArgumentType() << " value, const ValidationUtils& utils)" << std::endl
<< "\t" << "{" << std::endl;
const Field& field = *it;
if ((field.Attributes & (FARequired)) || field.Type.IsName) {
if (field.Attributes & FARequired) {
if (field.Type.GetRealType().find("::Ptr") != std::string::npos)
std::cout << "\t\t" << "if (!value)" << std::endl;
else
std::cout << "\t\t" << "if (value.IsEmpty())" << std::endl;
std::cout << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl;
}
if (field.Type.IsName) {
std::cout << "\t\t" << "String ref = value;" << std::endl
<< "\t\t" << "if (!ref.IsEmpty() && !utils.ValidateName(\"" << field.Type.TypeName << "\", ref))" << std::endl
<< "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of(\"" << field.Name << "\"), \"Object '\" + ref + \"' of type '" << field.Type.TypeName
<< "' does not exist.\"));" << std::endl;
}
}
std::cout << "\t" << "}" << std::endl << std::endl;
}
if (!klass.Fields.empty()) {
/* constructor */
@ -389,7 +446,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
if (!klass.Parent.empty())
std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
<< "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
<< "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
std::cout << "\t\t" << "switch (";
@ -406,7 +463,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
<< "\t\t\t\t" << "Set" << it->GetFriendlyName() << "(";
if (it->Attributes & FAEnum)
std::cout << "static_cast<" << it->Type << ">(static_cast<int>(";
std::cout << "static_cast<" << it->Type.GetRealType() << ">(static_cast<int>(";
std::cout << "value";
@ -465,7 +522,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
prot = "public";
std::cout << prot << ":" << std::endl
<< "\t" << "virtual " << it->Type << " Get" << it->GetFriendlyName() << "(void) const";
<< "\t" << "virtual " << it->Type.GetRealType() << " Get" << it->GetFriendlyName() << "(void) const";
if (it->PureGetAccessor) {
std::cout << " = 0;" << std::endl;
@ -494,14 +551,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
prot = "public";
std::cout << prot << ":" << std::endl
<< "\t" << "virtual void Set" << it->GetFriendlyName() << "(";
if (it->Type == "bool" || it->Type == "double" || it->Type == "int")
std::cout << it->Type;
else
std::cout << "const " << it->Type << "&";
std::cout << " value)" << std::endl;
<< "\t" << "virtual void Set" << it->GetFriendlyName() << "(" << it->Type.GetArgumentType() << " value)" << std::endl;
if (it->PureSetAccessor) {
std::cout << " = 0;" << std::endl;
@ -519,26 +569,32 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
/* default */
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
std::string prot;
std::string realType = it->Type.GetRealType();
std::cout << "private:" << std::endl
<< "\t" << it->Type << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
<< "\t" << realType << " GetDefault" << it->GetFriendlyName() << "(void) const" << std::endl
<< "\t" << "{" << std::endl;
if (it->DefaultAccessor.empty())
std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
std::cout << "\t\t" << "return " << realType << "();" << std::endl;
else
std::cout << it->DefaultAccessor << std::endl;
std::cout << "\t" << "}" << std::endl;
}
/* validators */
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
std::cout << "protected:" << std::endl
<< "\t" << "virtual void Validate" << it->GetFriendlyName() << "(" << it->Type.GetArgumentType() << " value, const ValidationUtils& utils);" << std::endl;
}
/* instance variables */
std::cout << "private:" << std::endl;
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
if (!(it->Attributes & FANoStorage))
std::cout << "\t" << it->Type << " m_" << it->GetFriendlyName() << ";" << std::endl;
std::cout << "\t" << it->Type.GetRealType() << " m_" << it->GetFriendlyName() << ";" << std::endl;
}
}
@ -549,6 +605,286 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
std::cout << "\t" << "friend class " << klass.TypeBase << ";" << std::endl;
std::cout << "};" << std::endl << std::endl;
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
m_MissingValidators[std::make_pair(klass.Name, it->GetFriendlyName())] = *it;
}
}
enum ValidatorType
{
ValidatorField,
ValidatorArray,
ValidatorDictionary
};
static void CodeGenValidator(const std::string& name, const std::string& klass, const std::vector<Rule>& rules, const std::string& field, const FieldType& fieldType, ValidatorType validatorType)
{
std::cout << "inline void TIValidate" << name << "(const intrusive_ptr<ObjectImpl<" << klass << "> >& object, ";
if (validatorType != ValidatorField)
std::cout << "const String& key, ";
bool static_known_attribute = false;
std::cout << fieldType.GetArgumentType() << " value, std::vector<String>& location, const ValidationUtils& utils)" << std::endl
<< "{" << std::endl;
if (validatorType == ValidatorField) {
static_known_attribute = true;
bool required = false;
for (std::vector<Rule>::size_type i = 0; i < rules.size(); i++) {
const Rule& rule = rules[i];
if ((rule.Attributes & RARequired) && rule.Pattern == field) {
required = true;
break;
}
}
if (fieldType.GetRealType() != "int" && fieldType.GetRealType() != "double") {
if (fieldType.GetRealType() == "Value" || fieldType.GetRealType() == "String")
std::cout << "\t" << "if (value.IsEmpty())" << std::endl;
else
std::cout << "\t" << "if (!value)" << std::endl;
if (required)
std::cout << "BOOST_THROW_EXCEPTION(ValidationError(this, location, \"This attribute must not be empty.\"));" << std::endl;
else
std::cout << "\t\t" << "return;" << std::endl;
std::cout << std::endl;
}
}
if (!static_known_attribute)
std::cout << "\t" << "bool known_attribute = false;" << std::endl;
bool type_check = false;
for (std::vector<Rule>::size_type i = 0; i < rules.size(); i++) {
const Rule& rule = rules[i];
if (rule.Attributes & RARequired)
continue;
if (validatorType == ValidatorField && rule.Pattern != field)
continue;
std::cout << "\t" << "do {" << std::endl;
if (validatorType != ValidatorField) {
if (rule.Pattern != "*") {
if (rule.Pattern.find_first_of("*?") != std::string::npos)
std::cout << "\t\t" << "if (!Utility::Match(\"" << rule.Pattern << "\", key))" << std::endl;
else
std::cout << "\t\t" << "if (key != \"" << rule.Pattern << "\")" << std::endl;
std::cout << "\t\t\t" << "break;" << std::endl;
} else
static_known_attribute = true;
if (!static_known_attribute)
std::cout << "\t\t" << "known_attribute = true;" << std::endl;
}
if (rule.IsName) {
std::cout << "\t\t" << "if (value.IsScalar()) {" << std::endl
<< "\t\t\t" << "if (utils.ValidateName(\"" << rule.Type << "\", value))" << std::endl
<< "\t\t\t\t" << "return;" << std::endl
<< "\t\t\t" << "else" << std::endl
<< "\t\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(object, location, \"Object '\" + value + \"' of type '" << rule.Type << "' does not exist.\"));" << std::endl
<< "\t\t" << "}" << std::endl;
}
if (fieldType.GetRealType() == "Value") {
if (rule.Type == "String")
std::cout << "\t\t" << "if (value.IsScalar())" << std::endl
<< "\t\t\t" << "return;" << std::endl;
else if (rule.Type == "Number") {
std::cout << "\t\t" << "try {" << std::endl
<< "\t\t\t" << "Convert::ToDouble(value);" << std::endl
<< "\t\t\t" << "return;" << std::endl
<< "\t\t" << "} catch (...) { }" << std::endl;
}
}
if (rule.Type == "Dictionary" || rule.Type == "Array" || rule.Type == "Function") {
if (fieldType.GetRealType() == "Value") {
std::cout << "\t\t" << "if (value.IsObjectType<" << rule.Type << ">()) {" << std::endl;
type_check = true;
} else if (fieldType.GetRealType() != rule.Type + "::Ptr") {
std::cout << "\t\t" << "if (dynamic_pointer_cast<" << rule.Type << ">(value)) {" << std::endl;
type_check = true;
}
if (!rule.Rules.empty()) {
bool indent = false;
if (rule.Type == "Dictionary") {
if (type_check)
std::cout << "\t\t\t" << "Dictionary::Ptr dict = value;" << std::endl;
else
std::cout << "\t\t" << "const Dictionary::Ptr& dict = value;" << std::endl;
std::cout << (type_check ? "\t" : "") << "\t\t" << "ObjectLock olock(dict);" << std::endl
<< (type_check ? "\t" : "") << "\t\t" << "BOOST_FOREACH(const Dictionary::Pair& kv, dict) {" << std::endl
<< (type_check ? "\t" : "") << "\t\t\t" << "const String& akey = kv.first;" << std::endl
<< (type_check ? "\t" : "") << "\t\t\t" << "const Value& avalue = kv.second;" << std::endl;
indent = true;
} else if (rule.Type == "Array") {
if (type_check)
std::cout << "\t\t\t" << "Array::Ptr arr = value;" << std::endl;
else
std::cout << "\t\t" << "const Array::Ptr& arr = value;" << std::endl;
std::cout << (type_check ? "\t" : "") << "\t\t" << "Array::SizeType anum = 0;" << std::endl
<< (type_check ? "\t" : "") << "\t\t" << "ObjectLock olock(arr);" << std::endl
<< (type_check ? "\t" : "") << "\t\t" << "BOOST_FOREACH(const Value& avalue, arr) {" << std::endl
<< (type_check ? "\t" : "") << "\t\t\t" << "String akey = Convert::ToString(anum);" << std::endl;
indent = true;
} else {
std::cout << (type_check ? "\t" : "") << "\t\t" << "String akey = \"\";" << std::endl
<< (type_check ? "\t" : "") << "\t\t" << "const Value& avalue = value;" << std::endl;
}
std::string subvalidator_prefix;
if (validatorType == ValidatorField)
subvalidator_prefix = klass;
else
subvalidator_prefix = name;
std::cout << (type_check ? "\t" : "") << (indent ? "\t" : "") << "\t\t" << "location.push_back(akey);" << std::endl
<< (type_check ? "\t" : "") << (indent ? "\t" : "") << "\t\t" << "TIValidate" << subvalidator_prefix << "_" << i << "(object, akey, avalue, location, utils);" << std::endl;
if (rule.Type == "Array")
std::cout << (type_check ? "\t" : "") << "\t\t\t" << "anum++;" << std::endl;
if (rule.Type == "Dictionary" || rule.Type == "Array")
std::cout << (type_check ? "\t" : "") << "\t\t" << "}" << std::endl;
for (std::vector<Rule>::size_type i = 0; i < rule.Rules.size(); i++) {
const Rule& srule = rule.Rules[i];
if ((srule.Attributes & RARequired) == 0)
continue;
if (rule.Type == "Dictionary") {
std::cout << (type_check ? "\t" : "") << "\t\t" << "if (dict.Get(\"" << srule.Pattern << "\").IsEmpty())" << std::endl
<< (type_check ? "\t" : "") << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(this, location, \"Required dictionary item '" << srule.Pattern << "' is not set.\"));" << std::endl;
} else if (rule.Type == "Array") {
int index = -1;
std::stringstream idxbuf;
idxbuf << srule.Pattern;
idxbuf >> index;
if (index == -1) {
std::cerr << "Invalid index for 'required' keyword: " << srule.Pattern;
std::exit(1);
}
std::cout << (type_check ? "\t" : "") << "\t\t" << "if (arr.GetLength() < " << (index + 1) << ")" << std::endl
<< (type_check ? "\t" : "") << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(this, location, \"Required index '" << index << "' is not set.\"));" << std::endl;
}
}
std::cout << (type_check ? "\t" : "") << (indent ? "\t" : "") << "\t\t" << "location.pop_back();" << std::endl;
}
std::cout << (type_check ? "\t" : "") << "\t\t" << "return;" << std::endl;
if (fieldType.GetRealType() == "Value" || fieldType.GetRealType() != rule.Type + "::Ptr")
std::cout << "\t\t" << "}" << std::endl;
}
std::cout << "\t" << "} while (0);" << std::endl << std::endl;
}
if (type_check || validatorType != ValidatorField) {
if (!static_known_attribute)
std::cout << "\t" << "if (!known_attribute)" << std::endl
<< "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(object, location, \"Invalid attribute: \" + key));" << std::endl
<< "\t" << "else" << std::endl;
std::cout << (!static_known_attribute ? "\t" : "") << "\t" << "BOOST_THROW_EXCEPTION(ValidationError(object, boost::assign::list_of(";
if (validatorType == ValidatorField)
std::cout << "\"" << field << "\"";
else
std::cout << "key";
std::cout << "), \"Invalid type.\"));" << std::endl;
}
std::cout << "}" << std::endl << std::endl;
}
static void CodeGenValidatorSubrules(const std::string& name, const std::string& klass, const std::vector<Rule>& rules)
{
for (std::vector<Rule>::size_type i = 0; i < rules.size(); i++) {
const Rule& rule = rules[i];
if (rule.Attributes & RARequired)
continue;
if (!rule.Rules.empty()) {
ValidatorType subtype;
if (rule.Type == "Array")
subtype = ValidatorArray;
else if (rule.Type == "Dictionary")
subtype = ValidatorDictionary;
else {
std::cerr << "Invalid sub-validator type: " << rule.Type << std::endl;
std::exit(EXIT_FAILURE);
}
std::ostringstream namebuf;
namebuf << name << "_" << i;
CodeGenValidatorSubrules(namebuf.str(), klass, rule.Rules);
FieldType ftype;
ftype.IsName = false;
ftype.TypeName = "Value";
CodeGenValidator(namebuf.str(), klass, rule.Rules, rule.Pattern, ftype, subtype);
}
}
}
void ClassCompiler::HandleValidator(const Validator& validator, const ClassDebugInfo&)
{
CodeGenValidatorSubrules(validator.Name, validator.Name, validator.Rules);
for (std::map<std::pair<std::string, std::string>, Field>::const_iterator it = m_MissingValidators.begin(); it != m_MissingValidators.end(); it++)
CodeGenValidator(it->first.first + it->first.second, it->first.first, validator.Rules, it->second.Name, it->second.Type, ValidatorField);
for (std::map<std::pair<std::string, std::string>, Field>::const_iterator it = m_MissingValidators.begin(); it != m_MissingValidators.end(); it++) {
std::cout << "inline void ObjectImpl<" << it->first.first << ">::Validate" << it->first.second << "(" << it->second.Type.GetArgumentType() << " value, const ValidationUtils& utils)" << std::endl
<< "{" << std::endl
<< "\t" << "SimpleValidate" << it->first.second << "(value, utils);" << std::endl
<< "\t" << "std::vector<String> location;" << std::endl
<< "\t" << "location.push_back(\"" << it->second.Name << "\");" << std::endl
<< "\t" << "TIValidate" << it->first.first << it->first.second << "(this, value, location, utils);" << std::endl
<< "}" << std::endl << std::endl;
}
m_MissingValidators.clear();
}
void ClassCompiler::HandleMissingValidators(void)
{
for (std::map<std::pair<std::string, std::string>, Field>::const_iterator it = m_MissingValidators.begin(); it != m_MissingValidators.end(); it++) {
std::cout << "inline void ObjectImpl<" << it->first.first << ">::Validate" << it->first.second << "(" << it->second.Type.GetArgumentType() << " value, const ValidationUtils& utils)" << std::endl
<< "{" << std::endl
<< "\t" << "SimpleValidate" << it->first.second << "(value, utils);" << std::endl
<< "}" << std::endl << std::endl;
}
m_MissingValidators.clear();
}
void ClassCompiler::CompileFile(const std::string& path)
@ -562,7 +898,7 @@ void ClassCompiler::CompileFile(const std::string& path)
return CompileStream(path, &stream);
}
std::string ClassCompiler::BaseName(const std::string& path)
std::string ClassCompiler::BaseName(const std::string& path)
{
char *dir = strdup(path.c_str());
std::string result;
@ -610,7 +946,12 @@ void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
<< "#include \"base/value.hpp\"" << std::endl
<< "#include \"base/array.hpp\"" << std::endl
<< "#include \"base/dictionary.hpp\"" << std::endl
<< "#include \"base/convert.hpp\"" << std::endl
<< "#include \"base/exception.hpp\"" << std::endl
<< "#include \"base/objectlock.hpp\"" << std::endl
<< "#include \"base/utility.hpp\"" << std::endl << std::endl
<< "#include <boost/foreach.hpp>" << std::endl
<< "#include <boost/assign/list_of.hpp>" << std::endl
<< "#ifdef _MSC_VER" << std::endl
<< "#pragma warning( push )" << std::endl
<< "#pragma warning( disable : 4244 )" << std::endl

View File

@ -24,6 +24,7 @@
#include <istream>
#include <vector>
#include <algorithm>
#include <map>
namespace icinga
{
@ -66,13 +67,38 @@ enum FieldAttribute
FASetProtected = 32,
FAInternal = 64,
FANoStorage = 128,
FALoadDependency = 256
FALoadDependency = 256,
FARequired = 512
};
struct FieldType
{
bool IsName;
std::string TypeName;
inline std::string GetRealType(void) const
{
if (IsName)
return "String";
else
return TypeName;
}
inline std::string GetArgumentType(void) const
{
std::string realType = GetRealType();
if (realType == "bool" || realType == "double" || realType == "int")
return realType;
else
return "const " + realType + "&";
}
};
struct Field
{
int Attributes;
std::string Type;
FieldType Type;
std::string Name;
std::string AlternativeName;
std::string GetAccessor;
@ -85,7 +111,7 @@ struct Field
: Attributes(0), PureGetAccessor(false), PureSetAccessor(false)
{ }
std::string GetFriendlyName(void) const
inline std::string GetFriendlyName(void) const
{
if (!AlternativeName.empty())
return AlternativeName;
@ -130,6 +156,27 @@ struct Klass
std::vector<std::string> LoadDependencies;
};
enum RuleAttribute
{
RARequired = 1
};
struct Rule
{
int Attributes;
bool IsName;
std::string Type;
std::string Pattern;
std::vector<Rule> Rules;
};
struct Validator
{
std::string Name;
std::vector<Rule> Rules;
};
class ClassCompiler
{
public:
@ -150,9 +197,11 @@ public:
void HandleInclude(const std::string& path, const ClassDebugInfo& locp);
void HandleAngleInclude(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);
void HandleNamespaceEnd(const ClassDebugInfo& locp);
void HandleCode(const std::string& code, const ClassDebugInfo& locp);
void HandleMissingValidators(void);
static void CompileFile(const std::string& path);
static void CompileStream(const std::string& path, std::istream *stream);
@ -164,6 +213,8 @@ private:
std::istream *m_Input;
void *m_Scanner;
std::map<std::pair<std::string, std::string>, Field> m_MissingValidators;
static unsigned long SDBM(const std::string& str, size_t len);
static std::string BaseName(const std::string& path);
static std::string FileNameToGuardName(const std::string& path);