00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <libxml/tree.h>
00021 #include <libxml/xmlwriter.h>
00022 #include <libxml/xmlreader.h>
00023 #include <pion/platform/ConfigManager.hpp>
00024 #include <pion/platform/Event.hpp>
00025 #include <pion/platform/Vocabulary.hpp>
00026 #include "XMLCodec.hpp"
00027
00028 using namespace pion::platform;
00029
00030
00031 namespace pion {
00032 namespace plugins {
00033
00034
00035
00036 const std::string XMLCodec::CONTENT_TYPE = "text/xml";
00037 const std::string XMLCodec::EVENT_TAG_ELEMENT_NAME = "EventTag";
00038 const std::string XMLCodec::EVENT_CONTAINER_TAG_ELEMENT_NAME = "EventContainerTag";
00039 const std::string XMLCodec::FIELD_ELEMENT_NAME = "Field";
00040 const std::string XMLCodec::TERM_ATTRIBUTE_NAME = "term";
00041 const std::string XMLCodec::DEFAULT_EVENT_TAG = "Event";
00042 const std::string XMLCodec::DEFAULT_EVENT_CONTAINER_TAG = "Events";
00043
00044
00045
00046
00047 CodecPtr XMLCodec::clone(void) const
00048 {
00049 XMLCodec *new_codec(new XMLCodec());
00050 new_codec->copyCodec(*this);
00051 for (CurrentFormat::const_iterator i = m_format.begin(); i != m_format.end(); ++i) {
00052 new_codec->mapFieldToTerm((*i)->field_name, (*i)->term);
00053 }
00054 new_codec->m_XML_field_ptr_map = m_XML_field_ptr_map;
00055 new_codec->m_event_container_tag = m_event_container_tag;
00056 new_codec->m_event_tag = m_event_tag;
00057 new_codec->m_no_events_written = true;
00058 return CodecPtr(new_codec);
00059 }
00060
00061 void XMLCodec::write(std::ostream& out, const Event& e)
00062 {
00063 if (m_no_events_written) {
00064 m_buf = xmlBufferCreate();
00065 if (m_buf == NULL)
00066 throw PionException("Error creating xmlBuffer");
00067
00068 m_xml_writer = xmlNewTextWriterMemory(m_buf, 0 );
00069 if (m_xml_writer == NULL)
00070 throw PionException("Error creating xmlTextWriter");
00071
00072
00073 if (xmlTextWriterSetIndent(m_xml_writer, 1) < 0)
00074 throw PionException("xmlTextWriter failed to turn on indentation");
00075 if (xmlTextWriterSetIndentString(m_xml_writer, (xmlChar*)"\t") < 0)
00076 throw PionException("xmlTextWriter failed to set the indent string");
00077
00078
00079 if (xmlTextWriterStartDocument(m_xml_writer, NULL, "UTF-8", NULL) < 0)
00080 throw PionException("xmlTextWriter failed to write the start of the document");
00081
00082 if (! m_event_container_tag.empty()) {
00083
00084 if (xmlTextWriterStartElement(m_xml_writer, (xmlChar*)m_event_container_tag.c_str()) < 0)
00085 throw PionException("xmlTextWriter failed to write a start-tag");
00086 }
00087 m_no_events_written = false;
00088 }
00089
00090 if (xmlTextWriterStartElement(m_xml_writer, (xmlChar*)m_event_tag.c_str()) < 0)
00091 throw PionException("xmlTextWriter failed to write an Event start-tag");
00092
00093
00094 CurrentFormat::const_iterator i;
00095 std::string value_str;
00096 const pion::platform::Event::BlobType* ss;
00097 for (i = m_format.begin(); i != m_format.end(); ++i) {
00098
00099 pion::platform::Vocabulary::TermRef term_ref = (*i)->term.term_ref;
00100 Event::ValuesRange range = e.equal_range(term_ref);
00101 xmlChar* field_name = (xmlChar*)(*i)->field_name.c_str();
00102
00103
00104 for (Event::ConstIterator i2 = range.first; i2 != range.second; ++i2) {
00105 int rc = 0;
00106 switch ((*i)->term.term_type) {
00107 case pion::platform::Vocabulary::TYPE_NULL:
00108 case pion::platform::Vocabulary::TYPE_OBJECT:
00109
00110 break;
00111 case pion::platform::Vocabulary::TYPE_INT8:
00112 case pion::platform::Vocabulary::TYPE_INT16:
00113 case pion::platform::Vocabulary::TYPE_INT32:
00114 rc = xmlTextWriterWriteFormatElement(m_xml_writer, field_name, "%d", boost::get<boost::int32_t>(i2->value));
00115 break;
00116 case pion::platform::Vocabulary::TYPE_INT64:
00117 value_str = boost::lexical_cast<std::string>(boost::get<boost::int64_t>(i2->value));
00118 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00119 break;
00120 case pion::platform::Vocabulary::TYPE_UINT8:
00121 case pion::platform::Vocabulary::TYPE_UINT16:
00122 case pion::platform::Vocabulary::TYPE_UINT32:
00123 rc = xmlTextWriterWriteFormatElement(m_xml_writer, field_name, "%d", boost::get<boost::uint32_t>(i2->value));
00124 break;
00125 case pion::platform::Vocabulary::TYPE_UINT64:
00126 value_str = boost::lexical_cast<std::string>(boost::get<boost::uint64_t>(i2->value));
00127 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00128 break;
00129 case pion::platform::Vocabulary::TYPE_FLOAT:
00130 rc = xmlTextWriterWriteFormatElement(m_xml_writer, field_name, "%g", boost::get<float>(i2->value));
00131 break;
00132 case pion::platform::Vocabulary::TYPE_DOUBLE:
00133
00134 value_str = boost::lexical_cast<std::string>(boost::get<double>(i2->value));
00135 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00136 break;
00137 case pion::platform::Vocabulary::TYPE_LONG_DOUBLE:
00138
00139 value_str = boost::lexical_cast<std::string>(boost::get<long double>(i2->value));
00140 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00141 break;
00142
00143 case pion::platform::Vocabulary::TYPE_SHORT_STRING:
00144 case pion::platform::Vocabulary::TYPE_STRING:
00145 case pion::platform::Vocabulary::TYPE_LONG_STRING:
00146 case pion::platform::Vocabulary::TYPE_BLOB:
00147 case pion::platform::Vocabulary::TYPE_ZBLOB:
00148 ss = &boost::get<const pion::platform::Event::BlobType&>(i2->value);
00149 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)ss->get());
00150 break;
00151 case pion::platform::Vocabulary::TYPE_CHAR:
00152 ss = &boost::get<const pion::platform::Event::BlobType&>(i2->value);
00153 if (ss->size() <= (*i)->term.term_size) {
00154 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)ss->get());
00155 } else {
00156 std::string trunc_str(ss->get(), (*i)->term.term_size);
00157 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)trunc_str.c_str());
00158 }
00159 break;
00160
00161 case pion::platform::Vocabulary::TYPE_DATE_TIME:
00162 case pion::platform::Vocabulary::TYPE_DATE:
00163 case pion::platform::Vocabulary::TYPE_TIME:
00164 (*i)->time_facet.toString(value_str, boost::get<const PionDateTime&>(i2->value));
00165 rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00166 break;
00167 }
00168 if (rc < 0)
00169 throw PionException("xmlTextWriter failed to write a Term element");
00170 }
00171 }
00172
00173 if (xmlTextWriterEndElement(m_xml_writer) < 0)
00174 throw PionException("xmlTextWriter failed to write an Event end-tag");
00175
00176 if (xmlTextWriterFlush(m_xml_writer) < 0)
00177 throw PionException("Error flushing XML writer");
00178 out.write((char*)m_buf->content, m_buf->use);
00179
00180 xmlBufferEmpty(m_buf);
00181
00182 if (m_flush_after_write)
00183 out.flush();
00184 }
00185
00186 void XMLCodec::finish(std::ostream& out)
00187 {
00188 if (m_no_events_written)
00189 return;
00190
00191
00192 if (xmlTextWriterEndDocument(m_xml_writer) < 0)
00193 throw PionException("xmlTextWriter failed to write end of document");
00194
00195
00196 if (xmlTextWriterFlush(m_xml_writer) < 0)
00197 throw PionException("Error flushing XML writer");
00198 out.write((char*)m_buf->content, m_buf->use);
00199
00200
00201 xmlFreeTextWriter(m_xml_writer);
00202 m_xml_writer = NULL;
00203 xmlBufferFree(m_buf);
00204 m_buf = NULL;
00205 }
00206
00207 int XMLCodec::xmlInputReadCallback(void* context, char* buffer, int len)
00208 {
00209
00210 streambuf_type* buf_ptr = ((std::istream*)context)->rdbuf();
00211 char* p = buffer;
00212 std::streamsize num_bytes_read;
00213 for (num_bytes_read = 0; num_bytes_read < len; ++num_bytes_read) {
00214 *p = buf_ptr->sbumpc();
00215 if (traits_type::eq_int_type(*p, traits_type::eof()))
00216 break;
00217 ++p;
00218 }
00219
00220 return num_bytes_read;
00221 }
00222
00223 int XMLCodec::xmlInputCloseCallback(void* context)
00224 {
00225 return 0;
00226 }
00227
00228 bool XMLCodec::read(std::istream& in, Event& e)
00229 {
00230 if (e.getType() != getEventType())
00231 throw WrongEventTypeException();
00232
00233 e.clear();
00234
00235 if (m_first_read_attempt) {
00236
00237 if (m_field_map.empty())
00238 throw PionException("Codec is not configured yet.");
00239
00240
00241 m_xml_reader = xmlReaderForIO(xmlInputReadCallback, xmlInputCloseCallback, (void*)(&in), NULL, NULL, XML_PARSE_NOBLANKS);
00242 if (!m_xml_reader)
00243 throw PionException("failed to create XML parser");
00244
00245 if (! m_event_container_tag.empty()) {
00246
00247 while (1) {
00248 int ret = xmlTextReaderRead(m_xml_reader);
00249 if (ret == 0) {
00250 return false;
00251 } else if (ret < 0) {
00252 throw PionException("XML parser error");
00253 }
00254
00255 if (xmlTextReaderNodeType(m_xml_reader) == 1) {
00256 const xmlChar* name = xmlTextReaderConstName(m_xml_reader);
00257 if (name == NULL)
00258 throw PionException("XML parser error");
00259 if (strcmp((char*)name, m_event_container_tag.c_str()) == 0)
00260 break;
00261 }
00262 }
00263 }
00264
00265 m_first_read_attempt = false;
00266 }
00267
00268
00269 while (1) {
00270 int ret = xmlTextReaderRead(m_xml_reader);
00271 if (ret == 0) {
00272
00273 if (m_event_container_tag.empty())
00274 in.setstate(std::ios::eofbit);
00275 return false;
00276 } else if (ret < 0) {
00277 throw PionException("XML parser error");
00278 }
00279 const xmlChar* name = xmlTextReaderConstName(m_xml_reader);
00280 if (xmlTextReaderNodeType(m_xml_reader) == 1) {
00281 if (name == NULL)
00282 throw PionException("XML parser error");
00283 if (strcmp((char*)name, m_event_tag.c_str()) == 0)
00284 break;
00285 } else if (xmlTextReaderNodeType(m_xml_reader) == 15) {
00286 if (name == NULL)
00287 throw PionException("XML parser error");
00288
00289 if (strcmp((char*)name, m_event_tag.c_str()) == 0) {
00290 return true;
00291 }
00292
00293 if (!m_event_container_tag.empty() && strcmp((char*)name, m_event_container_tag.c_str()) == 0) {
00294
00295
00296
00297 in.setstate(std::ios::eofbit);
00298 return false;
00299 }
00300 }
00301 }
00302
00303
00304 std::string open_element_name;
00305 while (1) {
00306 if (xmlTextReaderRead(m_xml_reader) != 1)
00307 throw PionException("XML parser error");
00308
00309
00310 const xmlChar* name = xmlTextReaderConstName(m_xml_reader);
00311 if (xmlTextReaderNodeType(m_xml_reader) == 15) {
00312 if (name == NULL)
00313 throw PionException("XML parser error");
00314 if (strcmp((char*)name, m_event_tag.c_str()) == 0)
00315 break;
00316 if (!m_event_container_tag.empty() && strcmp((char*)name, m_event_container_tag.c_str()) == 0) {
00317
00318 in.setstate(std::ios::eofbit);
00319 return true;
00320 }
00321 if (strcmp((char*)name, open_element_name.c_str()) == 0)
00322 open_element_name.clear();
00323 } else if (xmlTextReaderNodeType(m_xml_reader) == 1) {
00324
00325 if (name == NULL)
00326 throw PionException("XML parser error");
00327 if (! open_element_name.empty())
00328 continue;
00329 if (xmlTextReaderIsEmptyElement(m_xml_reader) == 1)
00330 continue;
00331 open_element_name = (char*)name;
00332
00333
00334 XMLCodec::FieldMap::const_iterator i = m_field_map.find(open_element_name);
00335 if (i == m_field_map.end())
00336 continue;
00337 const pion::platform::Vocabulary::Term& term = i->second->term;
00338
00339
00340 std::string value_str;
00341 bool found_end_of_field = false;
00342 while (!found_end_of_field) {
00343 if (xmlTextReaderRead(m_xml_reader) != 1)
00344 throw PionException("XML parser error");
00345 switch (xmlTextReaderNodeType(m_xml_reader)) {
00346 case 1:
00347 name = xmlTextReaderConstName(m_xml_reader);
00348 if (name) {
00349 value_str += '<';
00350 value_str += (char*) name;
00351 value_str += '>';
00352 }
00353 break;
00354
00355 case 15:
00356 name = xmlTextReaderConstName(m_xml_reader);
00357 if (name) {
00358 if (strcmp((char*)name, open_element_name.c_str()) == 0) {
00359
00360 open_element_name.clear();
00361 found_end_of_field = true;
00362 break;
00363 } else {
00364 value_str += "</";
00365 value_str += (char*) name;
00366 value_str += '>';
00367 }
00368 }
00369 break;
00370
00371 case 3:
00372 case 4:
00373 name = xmlTextReaderValue(m_xml_reader);
00374 if (name) {
00375 value_str += (char*) name;
00376 }
00377 break;
00378
00379 default:
00380 break;
00381 }
00382 }
00383
00384 switch (term.term_type) {
00385 case pion::platform::Vocabulary::TYPE_NULL:
00386 case pion::platform::Vocabulary::TYPE_OBJECT:
00387
00388 break;
00389 case pion::platform::Vocabulary::TYPE_INT8:
00390 case pion::platform::Vocabulary::TYPE_INT16:
00391 case pion::platform::Vocabulary::TYPE_INT32:
00392 e.setInt(term.term_ref, boost::lexical_cast<boost::int32_t>(value_str));
00393 break;
00394 case pion::platform::Vocabulary::TYPE_INT64:
00395 e.setBigInt(term.term_ref, boost::lexical_cast<boost::int64_t>(value_str));
00396 break;
00397 case pion::platform::Vocabulary::TYPE_UINT8:
00398 case pion::platform::Vocabulary::TYPE_UINT16:
00399 case pion::platform::Vocabulary::TYPE_UINT32:
00400 e.setUInt(term.term_ref, boost::lexical_cast<boost::uint32_t>(value_str));
00401 break;
00402 case pion::platform::Vocabulary::TYPE_UINT64:
00403 e.setUBigInt(term.term_ref, boost::lexical_cast<boost::uint64_t>(value_str));
00404 break;
00405 case pion::platform::Vocabulary::TYPE_FLOAT:
00406 e.setFloat(term.term_ref, boost::lexical_cast<float>(value_str));
00407 break;
00408 case pion::platform::Vocabulary::TYPE_DOUBLE:
00409 e.setDouble(term.term_ref, boost::lexical_cast<double>(value_str));
00410 break;
00411 case pion::platform::Vocabulary::TYPE_LONG_DOUBLE:
00412 e.setLongDouble(term.term_ref, boost::lexical_cast<long double>(value_str));
00413 break;
00414 case pion::platform::Vocabulary::TYPE_SHORT_STRING:
00415 case pion::platform::Vocabulary::TYPE_STRING:
00416 case pion::platform::Vocabulary::TYPE_LONG_STRING:
00417 case pion::platform::Vocabulary::TYPE_BLOB:
00418 case pion::platform::Vocabulary::TYPE_ZBLOB:
00419 e.setString(term.term_ref, value_str);
00420 break;
00421 case pion::platform::Vocabulary::TYPE_CHAR:
00422 if (value_str.size() > term.term_size) {
00423 e.setString(term.term_ref, std::string(value_str, 0, term.term_size));
00424 } else {
00425 e.setString(term.term_ref, value_str);
00426 }
00427 break;
00428 case pion::platform::Vocabulary::TYPE_DATE_TIME:
00429 case pion::platform::Vocabulary::TYPE_DATE:
00430 case pion::platform::Vocabulary::TYPE_TIME:
00431 {
00432 PionDateTime dt;
00433 m_XML_field_ptr_map[term.term_ref]->time_facet.fromString(value_str, dt);
00434 e.setDateTime(term.term_ref, dt);
00435 break;
00436 }
00437 }
00438 }
00439 }
00440
00441 return true;
00442 }
00443
00444 void XMLCodec::setConfig(const Vocabulary& v, const xmlNodePtr config_ptr)
00445 {
00446
00447 reset();
00448 Codec::setConfig(v, config_ptr);
00449
00450
00451 if (! ConfigManager::getConfigOption(EVENT_TAG_ELEMENT_NAME, m_event_tag, config_ptr)) {
00452 m_event_tag = DEFAULT_EVENT_TAG;
00453 }
00454 if (! ConfigManager::getConfigOption(EVENT_CONTAINER_TAG_ELEMENT_NAME, m_event_container_tag, config_ptr)) {
00455 if (ConfigManager::findConfigNodeByName(EVENT_CONTAINER_TAG_ELEMENT_NAME, config_ptr)) {
00456 m_event_container_tag = "";
00457 } else {
00458 m_event_container_tag = DEFAULT_EVENT_CONTAINER_TAG;
00459 }
00460 }
00461
00462
00463 xmlNodePtr codec_field_node = config_ptr;
00464 while ( (codec_field_node = ConfigManager::findConfigNodeByName(FIELD_ELEMENT_NAME, codec_field_node)) != NULL) {
00465
00466
00467
00468 xmlChar *xml_char_ptr = xmlNodeGetContent(codec_field_node);
00469 if (xml_char_ptr == NULL || xml_char_ptr[0] == '\0') {
00470 if (xml_char_ptr != NULL)
00471 xmlFree(xml_char_ptr);
00472 throw EmptyFieldException(getId());
00473 }
00474 const std::string field_name(reinterpret_cast<char*>(xml_char_ptr));
00475 xmlFree(xml_char_ptr);
00476
00477
00478 xml_char_ptr = xmlGetProp(codec_field_node, reinterpret_cast<const xmlChar*>(TERM_ATTRIBUTE_NAME.c_str()));
00479 if (xml_char_ptr == NULL || xml_char_ptr[0] == '\0') {
00480 if (xml_char_ptr != NULL)
00481 xmlFree(xml_char_ptr);
00482 throw EmptyTermException(getId());
00483 }
00484 const std::string term_id(reinterpret_cast<char*>(xml_char_ptr));
00485 xmlFree(xml_char_ptr);
00486
00487
00488 const Vocabulary::TermRef term_ref = v.findTerm(term_id);
00489 if (term_ref == Vocabulary::UNDEFINED_TERM_REF)
00490 throw UnknownTermException(term_id);
00491
00492
00493 mapFieldToTerm(field_name, v[term_ref]);
00494
00495
00496 codec_field_node = codec_field_node->next;
00497 }
00498
00499 m_XML_field_ptr_map.clear();
00500 for (FieldMap::const_iterator i = m_field_map.begin(); i != m_field_map.end(); ++i) {
00501 if (m_XML_field_ptr_map.find(i->second->term.term_ref) != m_XML_field_ptr_map.end())
00502 throw PionException("Duplicate Field Term");
00503 m_XML_field_ptr_map[i->second->term.term_ref] = i->second;
00504 }
00505 }
00506
00507 void XMLCodec::updateVocabulary(const Vocabulary& v)
00508 {
00509
00510 Codec::updateVocabulary(v);
00511
00513 for (CurrentFormat::iterator i = m_format.begin(); i != m_format.end(); ++i) {
00514
00515 v.refreshTerm((*i)->term);
00516
00517
00518 switch ((*i)->term.term_type) {
00519 case pion::platform::Vocabulary::TYPE_DATE_TIME:
00520 case pion::platform::Vocabulary::TYPE_DATE:
00521 case pion::platform::Vocabulary::TYPE_TIME:
00522 (*i)->time_facet.setFormat((*i)->term.term_format);
00523 break;
00524 default:
00525 break;
00526 }
00527 }
00528 }
00529
00530
00531 }
00532 }
00533
00534
00536 extern "C" PION_PLUGIN_API pion::platform::Codec *pion_create_XMLCodec(void) {
00537 return new pion::plugins::XMLCodec();
00538 }
00539
00541 extern "C" PION_PLUGIN_API void pion_destroy_XMLCodec(pion::plugins::XMLCodec *codec_ptr) {
00542 delete codec_ptr;
00543 }