OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ifmap_server_parser.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <stdint.h>
7 
8 #include <pugixml/pugixml.hpp>
9 #include "db/db.h"
11 #include "ifmap/ifmap_log.h"
12 #include "ifmap/ifmap_log_types.h"
13 
14 using namespace std;
15 using namespace pugi;
16 
18 
19 static const char *NodeName(const xml_node &node) {
20  const char *name = node.name();
21  // strip namespace
22  const char *dot = strchr(name, ':');
23  if (dot != NULL) {
24  name = dot + 1;
25  }
26  return name;
27 }
28 
30  ModuleMap::iterator loc = module_map_.find(module);
31  if (loc != module_map_.end()) {
32  return loc->second;
33  }
34  IFMapServerParser *parser = new IFMapServerParser();
35  module_map_.insert(make_pair(module, parser));
36  return parser;
37 }
38 
39 void IFMapServerParser::DeleteInstance(const string &module) {
40  ModuleMap::iterator loc = module_map_.find(module);
41  if (loc == module_map_.end()) {
42  return;
43  }
44 
45  delete loc->second;
46  module_map_.erase(loc);
47 }
48 
49 void IFMapServerParser::MetadataRegister(const string &metadata,
50  MetadataParseFn parser) {
51  pair<MetadataParseMap::iterator, bool> result =
52  metadata_map_.insert(make_pair(metadata, parser));
53  assert(result.second);
54 }
55 
56 void IFMapServerParser::MetadataClear(const string &module) {
57  metadata_map_.clear();
58  DeleteInstance(module);
59 }
60 
61 static string ParseIdentifier(const xml_node &node) {
62  string id(node.attribute("name").value());
63  return id;
64 }
65 
66 void IFMapServerParser::SetOrigin(struct DBRequest *result) const {
68  static_cast<IFMapServerTable::RequestData *>(result->data.get());
70 }
71 
72 bool IFMapServerParser::ParseMetadata(const pugi::xml_node &node,
73  struct DBRequest *result) const {
75  static_cast<IFMapServerTable::RequestData *>(result->data.get());
76  const char *name = NodeName(node);
77  MetadataParseMap::const_iterator loc = metadata_map_.find(name);
78  if (loc == metadata_map_.end()) {
79  return false;
80  }
81  std::unique_ptr<AutogenProperty> pvalue;
82  bool success = (loc->second)(node, &pvalue);
83  if (!success) {
84  return false;
85  }
86  if (data == NULL) {
87  data = new IFMapServerTable::RequestData();
88  result->data.reset(data);
89  }
90  data->metadata = name;
91  data->content.reset(pvalue.release());
92  return true;
93 }
94 
95 // Expect the identifier name to be [contrail:]type:name
96 static void IdentifierNsTypeName(const string &id, string *id_type,
97  string *id_name) {
98  size_t ns = id.find("contrail:");
99  size_t start = (ns == 0) ? sizeof("contrail:") - 1: 0;
100  size_t loc = id.find(':', start);
101  if (loc != string::npos) {
102  *id_type = string(id, start, loc - start);
103  *id_name = string(id, loc + 1, id.size() - (loc + 1));
104  } else {
105  *id_name = id;
106  }
107 }
108 
110  DBRequest *request = new DBRequest();
111  request->oper = src->oper;
112  IFMapTable::RequestKey *src_key =
113  static_cast<IFMapTable::RequestKey *>(src->key.get());
114  if (src_key != NULL) {
115  IFMapTable::RequestKey *dst_key =
117  dst_key->id_type = src_key->id_type;
118  dst_key->id_name = src_key->id_name;
119  request->key.reset(dst_key);
120  }
121 
123  static_cast<IFMapServerTable::RequestData *>(src->data.get());
124  if (src_data) {
127  dst_data->id_type = src_data->id_type;
128  dst_data->id_name = src_data->id_name;
129  request->data.reset(dst_data);
130  }
131  return request;
132 }
133 
135  const xml_node &parent, bool add_change, RequestList *list) const {
136  unique_ptr<DBRequest> request(new DBRequest);
137  request->oper = (add_change ? DBRequest::DB_ENTRY_ADD_CHANGE :
139  IFMapTable::RequestKey *key = NULL;
140  IFMapServerTable::RequestData *data = NULL;
141  int idcount = 0;
142  bool has_meta = false;
143  for (xml_node node = parent.first_child(); node;
144  node = node.next_sibling()) {
145  const char *name = NodeName(node);
146  if (strcmp(name, "identity") == 0) {
147  string id = ParseIdentifier(node);
148  switch (idcount) {
149  case 0:
150  key = new IFMapTable::RequestKey();
151  request->key.reset(key);
152  IdentifierNsTypeName(id, &key->id_type, &key->id_name);
153  break;
154  case 1:
155  data = new IFMapServerTable::RequestData();
156  request->data.reset(data);
157  IdentifierNsTypeName(id, &data->id_type, &data->id_name);
158  break;
159  default:
160  return false;
161  }
162  idcount++;
163  continue;
164  }
165  if (strcmp(name, "metadata") == 0) {
166  if (has_meta) {
167  return false;
168  }
169  has_meta = true;
170  for (xml_node meta = node.first_child(); meta;
171  meta = meta.next_sibling()) {
172  if (ParseMetadata(meta, request.get())) {
173  SetOrigin(request.get());
174  DBRequest *current = request.release();
175  if (meta.next_sibling()) {
176  request.reset(IFMapServerRequestClone(current));
177  }
178  list->push_back(current);
179  }
180  }
181  }
182  }
183 
184  if (idcount == 0 || !has_meta) {
185  return false;
186  }
187  return true;
188 }
189 
191  const xml_document &xdoc, RequestList *list) const {
192  xml_node current = xdoc.first_child();
193  while (current) {
194  bool add_change;
195  if (strcmp(NodeName(current), "updateResult") == 0 ||
196  strcmp(NodeName(current), "searchResult") == 0 ||
197  strcmp(NodeName(current), "deleteResult") == 0) {
198 
199  if (strcmp(NodeName(current), "deleteResult") == 0) {
200  add_change = false;
201  } else {
202  add_change = true;
203  }
204  xml_node result = current;
205  for (xml_node node = result.first_child(); node;
206  node = node.next_sibling()) {
207  ParseResultItem(node, add_change, list);
208  }
209  current = current.next_sibling();
210  } else {
211  current = current.first_child();
212  }
213  }
214 }
215 
216 // Called in the context of the ifmap client thread.
217 bool IFMapServerParser::Receive(DB *db, const char *data, size_t length,
218  uint64_t sequence_number) {
219  xml_document xdoc;
220  pugi::xml_parse_result result = xdoc.load_buffer(data, length);
221  if (!result) {
222  IFMAP_WARN(IFMapXmlLoadError, "Unable to load XML document", length);
223  return false;
224  }
225 
227  ParseResults(xdoc, &requests);
228 
229  while (!requests.empty()) {
230  unique_ptr<DBRequest> req(requests.front());
231  requests.pop_front();
232 
234  static_cast<IFMapTable::RequestKey *>(req->key.get());
235  key->id_seq_num = sequence_number;
236 
237  IFMapTable *table = IFMapTable::FindTable(db, key->id_type);
238  if (table != NULL) {
239  table->Enqueue(req.get());
240  } else {
241  IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table", key->id_type);
242  }
243  }
244  return true;
245 }
boost::function< bool(const pugi::xml_node &, std::unique_ptr< AutogenProperty > *) > MetadataParseFn
bool ParseMetadata(const pugi::xml_node &node, struct DBRequest *result) const
void MetadataRegister(const std::string &metadata, MetadataParseFn parser)
std::map< std::string, IFMapServerParser * > ModuleMap
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
bool Enqueue(DBRequest *req)
Definition: db_table.cc:194
void SetOrigin(struct DBRequest *result) const
std::unique_ptr< AutogenProperty > content
Definition: db.h:24
void set_origin(Origin in_origin)
Definition: ifmap_origin.h:21
static ModuleMap module_map_
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
DBOperation oper
Definition: db_table.h:42
static void IdentifierNsTypeName(const string &id, string *id_type, string *id_name)
void MetadataClear(const std::string &module)
bool Receive(DB *db, const char *data, size_t length, uint64_t sequence_number)
#define IFMAP_WARN(obj,...)
Definition: ifmap_log.h:72
void ParseResults(const pugi::xml_document &xdoc, RequestList *list) const
std::list< struct DBRequest * > RequestList
static IFMapTable * FindTable(DB *db, const std::string &element_type)
Definition: ifmap_table.cc:39
static IFMapServerParser * GetInstance(const std::string &module)
static DBRequest * IFMapServerRequestClone(const DBRequest *src)
static string ParseIdentifier(const xml_node &node)
static const char * NodeName(const xml_node &node)
#define IFMAP_TRACE(obj,...)
Definition: ifmap_log.h:26
bool ParseResultItem(const pugi::xml_node &parent, bool add_change, RequestList *list) const
static void DeleteInstance(const std::string &module)