2019-02-25 14:48:22 +01:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2013-11-04 23:14:34 +01:00
2014-05-25 16:23:35 +02:00
# include "base/serializer.hpp"
# include "base/type.hpp"
# include "base/application.hpp"
# include "base/objectlock.hpp"
2018-07-05 14:04:04 +02:00
# include "base/convert.hpp"
# include "base/exception.hpp"
2018-08-07 13:55:41 +02:00
# include "base/namespace.hpp"
2018-07-05 14:04:04 +02:00
# include <boost/algorithm/string/join.hpp>
# include <deque>
2013-11-04 23:14:34 +01:00
using namespace icinga ;
2018-07-05 14:04:04 +02:00
struct SerializeStackEntry
{
String Name ;
Value Val ;
} ;
CircularReferenceError : : CircularReferenceError ( String message , std : : vector < String > path )
: m_Message ( message ) , m_Path ( path )
{ }
const char * CircularReferenceError : : what ( void ) const throw ( )
{
return m_Message . CStr ( ) ;
}
std : : vector < String > CircularReferenceError : : GetPath ( ) const
{
return m_Path ;
}
struct SerializeStack
{
std : : deque < SerializeStackEntry > Entries ;
inline void Push ( const String & name , const Value & val )
{
Object : : Ptr obj ;
if ( val . IsObject ( ) )
obj = val ;
if ( obj ) {
for ( const auto & entry : Entries ) {
if ( entry . Val = = obj ) {
std : : vector < String > path ;
for ( const auto & entry : Entries )
path . push_back ( entry . Name ) ;
path . push_back ( name ) ;
BOOST_THROW_EXCEPTION ( CircularReferenceError ( " Cannot serialize object which recursively refers to itself. Attribute path which leads to the cycle: " + boost : : algorithm : : join ( path , " -> " ) , path ) ) ;
}
}
}
Entries . push_back ( { name , obj } ) ;
}
inline void Pop ( )
{
Entries . pop_back ( ) ;
}
} ;
static Value SerializeInternal ( const Value & value , int attributeTypes , SerializeStack & stack ) ;
static Array : : Ptr SerializeArray ( const Array : : Ptr & input , int attributeTypes , SerializeStack & stack )
2013-11-08 11:17:46 +01:00
{
2018-01-11 11:17:38 +01:00
ArrayData result ;
result . reserve ( input - > GetLength ( ) ) ;
2013-11-08 11:17:46 +01:00
ObjectLock olock ( input ) ;
2018-07-05 14:04:04 +02:00
int index = 0 ;
2016-08-25 06:19:44 +02:00
for ( const Value & value : input ) {
2018-07-05 14:04:04 +02:00
stack . Push ( Convert : : ToString ( index ) , value ) ;
result . emplace_back ( SerializeInternal ( value , attributeTypes , stack ) ) ;
stack . Pop ( ) ;
index + + ;
2013-11-08 11:17:46 +01:00
}
2018-01-11 11:17:38 +01:00
return new Array ( std : : move ( result ) ) ;
2013-11-08 11:17:46 +01:00
}
2018-07-05 14:04:04 +02:00
static Dictionary : : Ptr SerializeDictionary ( const Dictionary : : Ptr & input , int attributeTypes , SerializeStack & stack )
2013-11-08 11:17:46 +01:00
{
2018-01-11 11:17:38 +01:00
DictionaryData result ;
result . reserve ( input - > GetLength ( ) ) ;
2013-11-08 11:17:46 +01:00
ObjectLock olock ( input ) ;
2016-08-25 06:19:44 +02:00
for ( const Dictionary : : Pair & kv : input ) {
2018-07-05 14:04:04 +02:00
stack . Push ( kv . first , kv . second ) ;
result . emplace_back ( kv . first , SerializeInternal ( kv . second , attributeTypes , stack ) ) ;
stack . Pop ( ) ;
2013-11-08 11:17:46 +01:00
}
2018-01-11 11:17:38 +01:00
return new Dictionary ( std : : move ( result ) ) ;
2013-11-08 11:17:46 +01:00
}
2018-08-07 13:55:41 +02:00
static Dictionary : : Ptr SerializeNamespace ( const Namespace : : Ptr & input , int attributeTypes , SerializeStack & stack )
{
DictionaryData result ;
ObjectLock olock ( input ) ;
for ( const Namespace : : Pair & kv : input ) {
Value val = kv . second - > Get ( ) ;
stack . Push ( kv . first , val ) ;
result . emplace_back ( kv . first , Serialize ( val , attributeTypes ) ) ;
stack . Pop ( ) ;
}
return new Dictionary ( std : : move ( result ) ) ;
}
2018-07-05 14:04:04 +02:00
static Object : : Ptr SerializeObject ( const Object : : Ptr & input , int attributeTypes , SerializeStack & stack )
2013-11-08 11:17:46 +01:00
{
2014-11-03 00:44:04 +01:00
Type : : Ptr type = input - > GetReflectionType ( ) ;
2013-11-08 11:17:46 +01:00
2014-12-13 21:41:17 +01:00
if ( ! type )
2017-11-30 08:36:35 +01:00
return nullptr ;
2013-11-08 11:17:46 +01:00
2018-01-11 11:17:38 +01:00
DictionaryData fields ;
fields . reserve ( type - > GetFieldCount ( ) + 1 ) ;
2013-11-04 23:14:34 +01:00
2019-04-28 22:13:19 +02:00
ObjectLock olock ( input ) ;
2013-11-04 23:14:34 +01:00
for ( int i = 0 ; i < type - > GetFieldCount ( ) ; i + + ) {
Field field = type - > GetFieldInfo ( i ) ;
2015-11-02 16:35:21 +01:00
if ( attributeTypes ! = 0 & & ( field . Attributes & attributeTypes ) = = 0 )
2013-11-04 23:14:34 +01:00
continue ;
2018-01-11 11:17:38 +01:00
if ( strcmp ( field . Name , " type " ) = = 0 )
continue ;
2018-07-05 14:04:04 +02:00
Value value = input - > GetField ( i ) ;
stack . Push ( field . Name , value ) ;
2019-05-01 12:09:24 +02:00
fields . emplace_back ( field . Name , SerializeInternal ( value , attributeTypes , stack ) ) ;
2018-07-05 14:04:04 +02:00
stack . Pop ( ) ;
2013-11-08 11:17:46 +01:00
}
2018-01-11 11:17:38 +01:00
fields . emplace_back ( " type " , type - > GetName ( ) ) ;
2013-11-08 11:17:46 +01:00
2018-01-11 11:17:38 +01:00
return new Dictionary ( std : : move ( fields ) ) ;
2013-11-08 11:17:46 +01:00
}
2013-12-18 10:18:57 +01:00
static Array : : Ptr DeserializeArray ( const Array : : Ptr & input , bool safe_mode , int attributeTypes )
2013-11-08 11:17:46 +01:00
{
2018-01-11 11:17:38 +01:00
ArrayData result ;
result . reserve ( input - > GetLength ( ) ) ;
2013-11-08 11:17:46 +01:00
ObjectLock olock ( input ) ;
2016-08-25 06:19:44 +02:00
for ( const Value & value : input ) {
2018-01-11 11:17:38 +01:00
result . emplace_back ( Deserialize ( value , safe_mode , attributeTypes ) ) ;
2013-11-08 11:17:46 +01:00
}
2018-01-11 11:17:38 +01:00
return new Array ( std : : move ( result ) ) ;
2013-11-08 11:17:46 +01:00
}
2013-12-18 10:18:57 +01:00
static Dictionary : : Ptr DeserializeDictionary ( const Dictionary : : Ptr & input , bool safe_mode , int attributeTypes )
2013-11-08 11:17:46 +01:00
{
2018-01-11 11:17:38 +01:00
DictionaryData result ;
result . reserve ( input - > GetLength ( ) ) ;
2013-11-08 11:17:46 +01:00
ObjectLock olock ( input ) ;
2016-08-25 06:19:44 +02:00
for ( const Dictionary : : Pair & kv : input ) {
2018-01-11 11:17:38 +01:00
result . emplace_back ( kv . first , Deserialize ( kv . second , safe_mode , attributeTypes ) ) ;
2013-11-04 23:14:34 +01:00
}
2018-01-11 11:17:38 +01:00
return new Dictionary ( std : : move ( result ) ) ;
2013-11-04 23:14:34 +01:00
}
2013-12-18 10:18:57 +01:00
static Object : : Ptr DeserializeObject ( const Object : : Ptr & object , const Dictionary : : Ptr & input , bool safe_mode , int attributeTypes )
2013-11-04 23:14:34 +01:00
{
2014-10-25 09:14:56 +02:00
if ( ! object & & safe_mode )
BOOST_THROW_EXCEPTION ( std : : runtime_error ( " Tried to instantiate object while safe mode is enabled. " ) ) ;
2014-11-03 00:44:04 +01:00
Type : : Ptr type ;
2013-11-08 11:17:46 +01:00
if ( object )
type = object - > GetReflectionType ( ) ;
else
2014-03-28 13:52:29 +01:00
type = Type : : GetByName ( input - > Get ( " type " ) ) ;
2013-11-08 11:17:46 +01:00
if ( ! type )
return object ;
2014-10-25 09:14:56 +02:00
Object : : Ptr instance ;
2017-12-13 12:54:14 +01:00
2014-10-25 09:14:56 +02:00
if ( object )
instance = object ;
else
2016-03-29 14:42:32 +02:00
instance = type - > Instantiate ( std : : vector < Value > ( ) ) ;
2013-11-04 23:14:34 +01:00
2014-03-29 23:03:19 +01:00
ObjectLock olock ( input ) ;
2016-08-25 06:19:44 +02:00
for ( const Dictionary : : Pair & kv : input ) {
2013-12-13 12:54:14 +01:00
if ( kv . first . IsEmpty ( ) )
continue ;
2013-11-04 23:14:34 +01:00
2013-12-13 12:54:14 +01:00
int fid = type - > GetFieldId ( kv . first ) ;
2017-12-13 12:54:14 +01:00
2013-12-13 12:54:14 +01:00
if ( fid < 0 )
2013-11-04 23:14:34 +01:00
continue ;
2013-12-13 12:54:14 +01:00
Field field = type - > GetFieldInfo ( fid ) ;
2013-12-03 09:59:21 +01:00
2013-12-13 12:54:14 +01:00
if ( ( field . Attributes & attributeTypes ) = = 0 )
2013-11-04 23:14:34 +01:00
continue ;
2013-11-09 18:30:17 +01:00
try {
2016-08-13 22:54:22 +02:00
instance - > SetField ( fid , Deserialize ( kv . second , safe_mode , attributeTypes ) , true ) ;
2013-11-09 18:30:17 +01:00
} catch ( const std : : exception & ) {
2013-12-13 12:54:14 +01:00
instance - > SetField ( fid , Empty ) ;
2013-11-09 18:30:17 +01:00
}
2013-11-04 23:14:34 +01:00
}
2013-11-08 11:17:46 +01:00
return instance ;
}
2018-07-05 14:04:04 +02:00
static Value SerializeInternal ( const Value & value , int attributeTypes , SerializeStack & stack )
2013-11-08 11:17:46 +01:00
{
if ( ! value . IsObject ( ) )
return value ;
Object : : Ptr input = value ;
Array : : Ptr array = dynamic_pointer_cast < Array > ( input ) ;
2017-12-14 15:37:20 +01:00
if ( array )
2018-07-05 14:04:04 +02:00
return SerializeArray ( array , attributeTypes , stack ) ;
2013-11-08 11:17:46 +01:00
Dictionary : : Ptr dict = dynamic_pointer_cast < Dictionary > ( input ) ;
2017-12-14 15:37:20 +01:00
if ( dict )
2018-07-05 14:04:04 +02:00
return SerializeDictionary ( dict , attributeTypes , stack ) ;
2018-08-07 13:55:41 +02:00
Namespace : : Ptr ns = dynamic_pointer_cast < Namespace > ( input ) ;
if ( ns )
return SerializeNamespace ( ns , attributeTypes , stack ) ;
2018-07-05 14:04:04 +02:00
return SerializeObject ( input , attributeTypes , stack ) ;
}
2013-11-08 11:17:46 +01:00
2018-07-05 14:04:04 +02:00
Value icinga : : Serialize ( const Value & value , int attributeTypes )
{
SerializeStack stack ;
return SerializeInternal ( value , attributeTypes , stack ) ;
2013-11-08 11:17:46 +01:00
}
2013-12-18 10:18:57 +01:00
Value icinga : : Deserialize ( const Value & value , bool safe_mode , int attributeTypes )
2013-11-08 11:17:46 +01:00
{
2017-11-30 08:36:35 +01:00
return Deserialize ( nullptr , value , safe_mode , attributeTypes ) ;
2013-11-08 11:17:46 +01:00
}
2013-12-18 10:18:57 +01:00
Value icinga : : Deserialize ( const Object : : Ptr & object , const Value & value , bool safe_mode , int attributeTypes )
2013-11-08 11:17:46 +01:00
{
if ( ! value . IsObject ( ) )
return value ;
Object : : Ptr input = value ;
Array : : Ptr array = dynamic_pointer_cast < Array > ( input ) ;
2017-12-14 15:37:20 +01:00
if ( array )
2013-12-18 10:18:57 +01:00
return DeserializeArray ( array , safe_mode , attributeTypes ) ;
2013-11-08 11:17:46 +01:00
Dictionary : : Ptr dict = dynamic_pointer_cast < Dictionary > ( input ) ;
2017-12-14 15:37:20 +01:00
ASSERT ( dict ) ;
2013-11-08 11:17:46 +01:00
2014-10-25 09:14:56 +02:00
if ( ( safe_mode & & ! object ) | | ! dict - > Contains ( " type " ) )
2013-12-18 10:18:57 +01:00
return DeserializeDictionary ( dict , safe_mode , attributeTypes ) ;
2014-10-25 09:14:56 +02:00
else
return DeserializeObject ( object , dict , safe_mode , attributeTypes ) ;
2013-11-04 23:14:34 +01:00
}