OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
config_cass2json_adapter.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3  */
4 
6 
7 #include <assert.h>
8 #include <boost/algorithm/string/predicate.hpp>
9 #include <boost/assign/list_of.hpp>
10 #include <string>
11 #include <iostream>
12 
13 #include "base/string_util.h"
15 #include "config_client_log.h"
16 #include "config_client_log_types.h"
17 #include "rapidjson/stringbuffer.h"
18 #include "rapidjson/writer.h"
19 
20 using boost::assign::list_of;
21 using contrail_rapidjson::Document;
22 using contrail_rapidjson::StringBuffer;
23 using contrail_rapidjson::Value;
24 using contrail_rapidjson::Writer;
25 using std::cout;
26 using std::endl;
27 using std::set;
28 using std::string;
29 
30 const string ConfigCass2JsonAdapter::fq_name_prefix = "fq_name";
31 const string ConfigCass2JsonAdapter::prop_prefix = "prop:";
32 const string ConfigCass2JsonAdapter::list_prop_prefix = "propl:";
33 const string ConfigCass2JsonAdapter::map_prop_prefix = "propm:";
34 const string ConfigCass2JsonAdapter::ref_prefix = "ref:";
35 const string ConfigCass2JsonAdapter::parent_prefix = "parent:";
36 const string ConfigCass2JsonAdapter::parent_type_prefix = "parent_type";
37 
39  list_of(prop_prefix)(map_prop_prefix)
40  (list_prop_prefix)(ref_prefix)(parent_prefix);
41 
43  getenv("CONTRAIL_CONFIG_ASSERT_ON_PARSE_ERROR") != NULL;
44 
45 #define CONFIG_PARSE_ASSERT(t, condition) \
46  do { \
47  if (condition) \
48  break; \
49  CONFIG_CLIENT_WARN_LOG(ConfigurationMalformed ## t ## Warning ## Log, \
50  Category::CONFIG_CLIENT, c.key, c.value, type_, uuid_); \
51  CONFIG_CLIENT_TRACE(ConfigurationMalformed ## t ## Warning ## Trace, \
52  c.key, c.value, type_, uuid_); \
53  cout << "CONFIG_PARSE_ERROR " << __FILE__ << ":" << __LINE__ << " "; \
54  cout << type_ << " " << c.key << " " << c.value << " "; \
55  cout << uuid_ << endl; \
56  if (assert_on_parse_error_) \
57  assert(false); \
58  return; \
59  } while (false)
60 
62  ConfigCassandraClient *cassandra_client, const string &obj_type,
63  const CassColumnKVVec &cdvec) : cassandra_client_(cassandra_client),
64  uuid_(uuid) {
65  CreateJsonString(obj_type, cdvec);
66 }
67 
69  const string &type, const Document &doc) : uuid_(uuid) {
73  Document::AllocatorType &a = json_document_.GetAllocator();
74  Value v;
75  v.CopyFrom(doc, a);
76 
77  Value vk;
78  json_document_.SetObject().AddMember(vk.SetString(type.c_str(), a),
79  v, a);
80 }
81 
82 string ConfigCass2JsonAdapter::GetJsonString(const Value &attr_value) {
83  StringBuffer buffer;
84  Writer<StringBuffer> writer(buffer);
85  attr_value.Accept(writer);
86  return buffer.GetString();
87 }
88 
89 void ConfigCass2JsonAdapter::AddOneEntry(Value *jsonObject,
90  const string &obj_type, const JsonAdapterDataType &c,
91  Document::AllocatorType &a) {
92 
93  // Process scalar property values.
94  if (boost::starts_with(c.key, prop_prefix)) {
95  string c_value = c.value;
96  if (c.key == "prop:bgpaas_session_attributes")
97  c_value = "\"\"";
98  Document prop_document(&a);
99  prop_document.Parse<0>(c_value.c_str());
100  CONFIG_PARSE_ASSERT(Property, !prop_document.HasParseError());
101  Value vk;
102  jsonObject->AddMember(
103  vk.SetString(c.key.substr(prop_prefix.size()).c_str(), a),
104  prop_document, a);
105  return;
106  }
107 
108  // Process property list and property map values.
109  bool is_map = false;
110  if ((is_map = boost::starts_with(c.key, map_prop_prefix)) ||
111  boost::starts_with(c.key, list_prop_prefix)) {
112  size_t from_front_pos = c.key.find(':');
113  size_t from_back_pos = c.key.rfind(':');
114  string prop_map = c.key.substr(from_front_pos + 1,
115  from_back_pos - from_front_pos - 1);
116  string wrapper = cassandra_client_->mgr()-> \
117  config_json_parser()->GetWrapperFieldName(type_,
118  prop_map);
119  if (wrapper.empty()) {
120  return;
121  }
122  if (!jsonObject->HasMember(prop_map.c_str())) {
123  Value v;
124  Value vk;
125  jsonObject->AddMember(
126  vk.SetString(prop_map.c_str(), a), v.SetObject(), a);
127  Value va;
128  Value vak;
129  (*jsonObject)[prop_map.c_str()].AddMember(
130  vak.SetString(wrapper.c_str(), a), va.SetArray(), a);
131  }
132 
133  Document map_document(&a);
134  map_document.Parse<0>(c.value.c_str());
135  if (is_map)
136  CONFIG_PARSE_ASSERT(PropertyMap, !map_document.HasParseError());
137  else
138  CONFIG_PARSE_ASSERT(PropertyList, !map_document.HasParseError());
139 
140  (*jsonObject)[prop_map.c_str()][wrapper.c_str()].PushBack(
141  map_document, a);
142  return;
143  }
144 
145  if (boost::starts_with(c.key, ref_prefix)) {
146  size_t from_front_pos = c.key.find(':');
147  size_t from_back_pos = c.key.rfind(':');
148  CONFIG_PARSE_ASSERT(Reference, from_front_pos != string::npos);
149  CONFIG_PARSE_ASSERT(Reference, from_back_pos != string::npos);
150  string ref_type = c.key.substr(from_front_pos + 1,
151  from_back_pos-from_front_pos - 1);
152  string ref_uuid = c.key.substr(from_back_pos + 1);
153  string fq_name_ref = c.ref_fq_name;
154  string r = ref_type + "_refs";
155  if (!jsonObject->HasMember(r.c_str())) {
156  Value v;
157  Value vk;
158  jsonObject->AddMember(vk.SetString(r.c_str(), a), v.SetArray(), a);
159  }
160 
161  Value v;
162  v.SetObject();
163 
164  Value vs1;
165  Value vs2;
166  v.AddMember("to", vs1.SetString(fq_name_ref.c_str(), a), a);
167  v.AddMember("uuid", vs2.SetString(ref_uuid.c_str(), a), a);
168 
169  bool link_with_attr =
170  cassandra_client_->mgr()->config_json_parser()->\ IsLinkWithAttr(obj_type, ref_type);
171  if (link_with_attr) {
172  Document ref_document(&a);
173  ref_document.Parse<0>(c.value.c_str());
174  CONFIG_PARSE_ASSERT(ReferenceLinkAttributes,
175  !ref_document.HasParseError());
176  CONFIG_PARSE_ASSERT(ReferenceLinkAttributes,
177  ref_document.HasMember("attr"));
178  Value &attr_value = ref_document["attr"];
179  if (!attr_value.IsNull()) {
180  v.AddMember("attr", attr_value, a);
181  } else {
182  Value vm;
183  v.AddMember("attr", vm.SetObject(), a);
184  }
185  } else {
186  Value vm;
187  v.AddMember("attr", vm.SetObject(), a);
188  }
189  (*jsonObject)[r.c_str()].PushBack(v, a);
190  return;
191  }
192 
193  if (boost::starts_with(c.key, parent_prefix)) {
194  size_t pos = c.key.rfind(':');
195  CONFIG_PARSE_ASSERT(Parent, pos != string::npos);
196  size_t type_pos = c.key.find(':');
197  CONFIG_PARSE_ASSERT(Parent, type_pos != string::npos);
198  Value v;
199  Value vk;
200  jsonObject->AddMember(vk.SetString(parent_type_prefix.c_str(), a),
201  v.SetString(c.key.substr(type_pos + 1,
202  pos-type_pos - 1).c_str(), a), a);
203  return;
204  }
205 
206  if (!c.key.compare(fq_name_prefix)) {
207  Document fq_name_document(&a);
208  fq_name_document.Parse<0>(c.value.c_str());
209  CONFIG_PARSE_ASSERT(FqName, !fq_name_document.HasParseError());
210  Value vk;
211  jsonObject->AddMember(vk.SetString(c.key.c_str(), a),
212  fq_name_document, a);
213  return;
214  }
215 
216  if (!c.key.compare("type")) {
217  // Prepend the 'type'. This is "our key", with value being the json
218  // sub-document containing all other columns.
219  CONFIG_PARSE_ASSERT(Type, type_ != obj_type);
220  type_ = c.value;
221  type_.erase(remove(type_.begin(), type_.end(), '\"'), type_.end());
222  return;
223  }
224 }
225 
226 void ConfigCass2JsonAdapter::CreateJsonString(const string &obj_type,
227  const CassColumnKVVec &cdvec) {
228  if (cdvec.empty())
229  return;
230  Document::AllocatorType &a = json_document_.GetAllocator();
231  Value jsonObject;
232  jsonObject.SetObject();
233 
234  // First look for and part "type" field. We usually expect it to be at the
235  // end as column keys are suppose to be allways sorted lexicographically.
236  size_t type_index = -1;
237  size_t i = cdvec.size();
238  while (i--) {
239  if (!cdvec[i].key.compare("type")) {
240  AddOneEntry(&jsonObject, obj_type, cdvec[i], a);
241  type_index = i;
242  break;
243  }
244  }
245 
246  if (type_.empty()) {
247 
248  CONFIG_CLIENT_WARN_LOG(ConfigurationMissingTypeWarningLog,
249  Category::CONFIG_CLIENT, uuid_, obj_type);
250  CONFIG_CLIENT_TRACE(ConfigurationMissingTypeWarningTrace, uuid_,
251  obj_type);
252  return;
253  }
254 
255  for (size_t i = 0; i < cdvec.size(); ++i) {
256  if (i != type_index)
257  AddOneEntry(&jsonObject, obj_type, cdvec[i], a);
258  }
259 
260  Value vk;
261  json_document_.SetObject().AddMember(vk.SetString(type_.c_str(), a),
262  jsonObject, a);
263 }
264 
static const std::string ref_prefix
ConfigJsonParserBase * config_json_parser()
#define CONFIG_CLIENT_WARN_LOG(obj, category,...)
static std::string GetJsonString(const contrail_rapidjson::Value &attr_value)
static const std::string list_prop_prefix
ConfigClientManager * mgr()
boost::uuids::uuid uuid
static const std::string prop_prefix
contrail_rapidjson::Document json_document_
static const std::set< std::string > allowed_properties
#define CONFIG_CLIENT_TRACE(obj,...)
static const std::string parent_type_prefix
void AddOneEntry(contrail_rapidjson::Value *jsonObject, const std::string &obj_type, const JsonAdapterDataType &c, contrail_rapidjson::Document::AllocatorType &a)
uint8_t type
Definition: load_balance.h:109
ConfigCassandraClient * cassandra_client_
std::vector< JsonAdapterDataType > CassColumnKVVec
static const std::string fq_name_prefix
static const std::string parent_prefix
static const std::string map_prop_prefix
void CreateJsonString(const std::string &obj_type, const CassColumnKVVec &cdvec)
ConfigCass2JsonAdapter(const std::string &uuid, ConfigCassandraClient *cassandra_client, const std::string &obj_type, const CassColumnKVVec &cdvec)
#define CONFIG_PARSE_ASSERT(t, condition)