platform/codecs/XMLCodec.hpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 
00020 #ifndef __PION_XMLCODEC_HEADER__
00021 #define __PION_XMLCODEC_HEADER__
00022 
00023 #include <vector>
00024 #include <map>
00025 #include <queue>
00026 #include <libxml/tree.h>
00027 #include <libxml/xmlwriter.h>
00028 #include <libxml/xmlreader.h>
00029 #include <pion/PionConfig.hpp>
00030 #include <pion/platform/Codec.hpp>
00031 
00032 
00033 namespace pion {        // begin namespace pion
00034 namespace plugins {     // begin namespace plugins
00035 
00036 
00041 class XMLCodec :
00042     public pion::platform::Codec
00043 {
00044 public:
00046     class EmptyFieldException : public PionException {
00047     public:
00048         EmptyFieldException(const std::string& codec_id)
00049             : PionException("XMLCodec configuration includes an empty field name: ", codec_id) {}
00050     };
00051 
00053     class EmptyTermException : public PionException {
00054     public:
00055         EmptyTermException(const std::string& codec_id)
00056             : PionException("XMLCodec configuration is missing a term identifier: ", codec_id) {}
00057     };
00058 
00059 
00061     XMLCodec(void) :
00062         pion::platform::Codec(),
00063         m_flush_after_write(false), m_xml_writer(NULL), m_buf(NULL), m_xml_reader(NULL),
00064         m_no_events_written(true), m_first_read_attempt(true)
00065     {}
00066     
00068     virtual ~XMLCodec() {
00069         if (m_xml_reader)
00070             xmlFreeTextReader(m_xml_reader);
00071         if (m_xml_writer)
00072             xmlFreeTextWriter(m_xml_writer);
00073         if (m_buf)
00074             xmlBufferFree(m_buf);
00075     }
00076     
00078     virtual const std::string& getContentType(void) const { return CONTENT_TYPE; }
00079 
00085     virtual pion::platform::CodecPtr clone(void) const;
00086 
00093     virtual void write(std::ostream& out, const pion::platform::Event& e);
00094 
00100     virtual void finish(std::ostream& out);
00101 
00109     virtual bool read(std::istream& in, pion::platform::Event& e);
00110 
00118     virtual void setConfig(const pion::platform::Vocabulary& v, const xmlNodePtr config_ptr);
00119 
00126     virtual void updateVocabulary(const pion::platform::Vocabulary& v);
00127 
00129     inline void reset(void) {
00130         m_field_map.clear();
00131         m_format.clear();
00132     }
00133     
00135     struct XMLField {
00136         XMLField(const std::string& f, const pion::platform::Vocabulary::Term& t)
00137             : field_name(f), term(t)
00138         {}
00139 
00141         std::string                         field_name;
00142 
00144         pion::platform::Vocabulary::Term    term;
00145 
00147         PionTimeFacet                       time_facet;
00148     };
00149 
00151     typedef boost::shared_ptr<XMLField>     XMLFieldPtr;
00152 
00154     typedef PION_HASH_MAP<std::string,
00155         XMLFieldPtr,
00156         PION_HASH_STRING>                   FieldMap;
00157 
00159     typedef std::vector<XMLFieldPtr>        CurrentFormat;
00160 
00161 private:
00162 
00164     typedef std::istream::traits_type       traits_type;
00165 
00167     typedef std::basic_streambuf<
00168         std::istream::char_type,
00169         std::istream::traits_type>          streambuf_type;
00170 
00177     inline void mapFieldToTerm(const std::string& field,
00178                                const pion::platform::Vocabulary::Term& term);
00179 
00180     // Callback for xmlReaderForIO() to read more data.
00181     static int  xmlInputReadCallback(void* context, char* buffer, int len);
00182 
00183     // Callback for xmlReaderForIO(), called when it's done reading.
00184     static int  xmlInputCloseCallback(void* context);
00185 
00186 
00188     static const std::string        CONTENT_TYPE;
00189 
00191     static const std::string        FIELD_ELEMENT_NAME;
00192 
00194     static const std::string        TERM_ATTRIBUTE_NAME;
00195 
00197     static const std::string        EVENT_TAG_ELEMENT_NAME;
00198 
00200     static const std::string        DEFAULT_EVENT_TAG;
00201 
00203     static const std::string        EVENT_CONTAINER_TAG_ELEMENT_NAME;
00204 
00206     static const std::string        DEFAULT_EVENT_CONTAINER_TAG;
00207 
00208 
00210     std::string                     m_event_tag;
00211 
00213     std::string                     m_event_container_tag;
00214 
00216     FieldMap                        m_field_map;
00217 
00219     std::map<pion::platform::Vocabulary::TermRef, XMLFieldPtr>
00220                                     m_XML_field_ptr_map;
00221 
00223     CurrentFormat                   m_format;
00224 
00226     bool                            m_flush_after_write;
00227 
00229     xmlTextWriterPtr                m_xml_writer;
00230 
00232     xmlBufferPtr                    m_buf;
00233 
00235     xmlTextReaderPtr                m_xml_reader;
00236 
00238     bool                            m_no_events_written;
00239 
00241     bool                            m_first_read_attempt;
00242 };
00243 
00244 
00245 // inline member functions for XMLCodec
00246 
00247 inline void XMLCodec::mapFieldToTerm(const std::string& field,
00248                                       const pion::platform::Vocabulary::Term& term)
00249 {
00250     if (m_field_map[field])
00251         throw PionException("Duplicate Field Name");
00252 
00253     // prepare a new XML field object
00254     XMLFieldPtr field_ptr(new XMLField(field, term));
00255     switch (term.term_type) {
00256         case pion::platform::Vocabulary::TYPE_DATE_TIME:
00257         case pion::platform::Vocabulary::TYPE_DATE:
00258         case pion::platform::Vocabulary::TYPE_TIME:
00259             field_ptr->time_facet.setFormat(term.term_format);
00260             break;
00261         default:
00262             break; // do nothing
00263     }
00264 
00265     // add it to the mapping of field names
00266     m_field_map[field] = field_ptr;
00267 
00268     // append the new field to the current format
00269     m_format.push_back(field_ptr);
00270 }
00271 
00272 }   // end namespace plugins
00273 }   // end namespace pion
00274 
00275 #endif

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7