Finalizing state to/from XML encoding and decoding
diff --git a/model/sync-diff-state.cc b/model/sync-diff-state.cc
index 5a53e81..75e0be5 100644
--- a/model/sync-diff-state.cc
+++ b/model/sync-diff-state.cc
@@ -79,32 +79,4 @@
m_leaves.insert (leaf);
}
-#ifdef _DEBUG
-#define DEBUG_ENDL os << "\n";
-#else
-#define DEBUG_ENDL
-#endif
-
-std::ostream &
-operator << (std::ostream &os, const DiffState &state)
-{
- os << "<state type=\"diff\">"; DEBUG_ENDL;
-
- BOOST_FOREACH (shared_ptr<const Leaf> _leaf, state.getLeaves ())
- {
- shared_ptr<const DiffLeaf> leaf = dynamic_pointer_cast<const DiffLeaf> (_leaf);
- BOOST_ASSERT (leaf != 0);
-
- os << "<item action=\"" << leaf->getOperation () << "\">"; DEBUG_ENDL;
- os << "<name>" << leaf->getInfo () << "</name>"; DEBUG_ENDL;
- if (leaf->getOperation () == UPDATE)
- {
- os << "<seq>" << leaf->getSeq () << "</seq>"; DEBUG_ENDL;
- }
- os << "</item>"; DEBUG_ENDL;
- }
- os << "</state>";
-}
-
-
} // ns3
diff --git a/model/sync-diff-state.h b/model/sync-diff-state.h
index 053be84..ac35625 100644
--- a/model/sync-diff-state.h
+++ b/model/sync-diff-state.h
@@ -97,15 +97,6 @@
DigestConstPtr m_digest;
};
-/**
- * @brief Formats an XML representation of the diff state
- * @param os output stream
- * @param state state
- * @returns output stream
- */
-std::ostream &
-operator << (std::ostream &os, const DiffState &state);
-
} // Sync
#endif // SYNC_DIFF_STATE_H
diff --git a/model/sync-full-state.cc b/model/sync-full-state.cc
index f53de39..e8a2149 100644
--- a/model/sync-full-state.cc
+++ b/model/sync-full-state.cc
@@ -117,25 +117,4 @@
m_leaves.erase (*info);
}
-#ifdef _DEBUG
-#define DEBUG_ENDL os << "\n";
-#else
-#define DEBUG_ENDL
-#endif
-
-std::ostream &
-operator << (std::ostream &os, const FullState &state)
-{
- os << "<state type=\"full\">"; DEBUG_ENDL;
-
- BOOST_FOREACH (shared_ptr<const Leaf> leaf, state.getLeaves ())
- {
- os << "<item>"; DEBUG_ENDL;
- os << "<name>" << leaf->getInfo () << "</name>"; DEBUG_ENDL;
- os << "<seq>" << leaf->getSeq () << "</seq>"; DEBUG_ENDL;
- os << "</item>"; DEBUG_ENDL;
- }
- os << "</state>";
-}
-
} // Sync
diff --git a/model/sync-full-state.h b/model/sync-full-state.h
index 96597d0..9769878 100644
--- a/model/sync-full-state.h
+++ b/model/sync-full-state.h
@@ -78,16 +78,6 @@
DigestPtr m_digest;
};
-/**
- * @brief Formats an XML representation of the full state
- * @param os output stream
- * @param state state
- * @returns output stream
- */
-std::ostream &
-operator << (std::ostream &os, const FullState &state);
-
-
} // Sync
#endif // SYNC_STATE_H
diff --git a/model/sync-global-function.cc b/model/sync-global-function.cc
deleted file mode 100644
index c01b682..0000000
--- a/model/sync-global-function.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012 University of California, Los Angeles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
- * 卞超轶 Chaoyi Bian <bcy@pku.edu.cn>
- * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
- */
-
-#define TIXML_USE_STL
-
-#include <string>
-#include <tinyxml.h>
-#include "sync-state.h"
-#include "sync-std-name-info.h"
-
-using namespace std;
-
-namespace Sync
-{
- string & operator >> (string &DataBuffer, State &state)
- {
- TiXmlDocument doc;
-
- doc.Parse(DataBuffer.c_str());
- for (TiXmlElement *iterator = doc.RootElement(); iterator != NULL; iterator = iterator->NextSiblingElement())
- {
- if (strcmp(iterator->Attribute("action"), "update") == 0)
- {
- TiXmlElement *name = iterator->FirstChildElement();
- TiXmlElement *session = name->NextSiblingElement();
- TiXmlElement *sequence = session->NextSiblingElement();
- NameInfoConstPtr info = StdNameInfo::FindOrCreate(name->GetText());
- SeqNo seqNo(atoi(session->GetText()), atoi(sequence->GetText()));
-
- state.update(info, seqNo);
- }
- else
- {
- TiXmlElement *name = iterator->FirstChildElement();
- NameInfoConstPtr info = StdNameInfo::FindOrCreate(name->GetText());
- state.remove(info);
- }
- }
-
- return DataBuffer;
- }
-}
diff --git a/model/sync-state.cc b/model/sync-state.cc
index 268a45f..5e09655 100644
--- a/model/sync-state.cc
+++ b/model/sync-state.cc
@@ -21,8 +21,102 @@
*/
#include "sync-state.h"
+#include "sync-diff-leaf.h"
+#include "sync-std-name-info.h"
+
#include <boost/assert.hpp>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/lexical_cast.hpp>
+
+#define TIXML_USE_STL
+#include <tinyxml.h>
+
+using namespace std;
+using namespace boost;
+
+typedef error_info<struct tag_errmsg, string> info_str;
namespace Sync {
+#ifdef _DEBUG
+#define DEBUG_ENDL os << "\n";
+#else
+#define DEBUG_ENDL
+#endif
+
+std::ostream &
+operator << (std::ostream &os, const State &state)
+{
+ os << "<state>"; DEBUG_ENDL;
+
+ BOOST_FOREACH (shared_ptr<const Leaf> leaf, state.getLeaves ().get<ordered> ())
+ {
+ shared_ptr<const DiffLeaf> diffLeaf = dynamic_pointer_cast<const DiffLeaf> (leaf);
+ if (diffLeaf != 0)
+ {
+ os << "<item action=\"" << diffLeaf->getOperation () << "\">"; DEBUG_ENDL;
+ }
+ else
+ {
+ os << "<item>"; DEBUG_ENDL;
+ }
+ os << "<name>" << leaf->getInfo () << "</name>"; DEBUG_ENDL;
+ if (diffLeaf == 0 || (diffLeaf != 0 && diffLeaf->getOperation () == UPDATE))
+ {
+ os << "<seq>" << leaf->getSeq () << "</seq>"; DEBUG_ENDL;
+ }
+ os << "</item>"; DEBUG_ENDL;
+ }
+ os << "</state>";
+}
+
+std::istream &
+operator >> (std::istream &in, State &state)
+{
+ TiXmlDocument doc;
+ in >> doc;
+
+ if (doc.RootElement() == 0)
+ BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("Empty XML"));
+
+ for (TiXmlElement *iterator = doc.RootElement()->FirstChildElement ("item");
+ iterator != 0;
+ iterator = iterator->NextSiblingElement("item"))
+ {
+ TiXmlElement *name = iterator->FirstChildElement ("name");
+ if (name == 0 || name->GetText() == 0)
+ BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<name> element is missing"));
+
+ NameInfoConstPtr info = StdNameInfo::FindOrCreate (name->GetText());
+
+ if (iterator->Attribute("action") == 0 || strcmp(iterator->Attribute("action"), "update") == 0)
+ {
+ TiXmlElement *seq = iterator->FirstChildElement ("seq");
+ if (seq == 0)
+ BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<seq> element is missing"));
+
+ TiXmlElement *session = seq->FirstChildElement ("session");
+ TiXmlElement *seqno = seq->FirstChildElement ("seqno");
+
+ if (session == 0 || session->GetText() == 0)
+ BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<session> element is missing"));
+ if (seqno == 0 || seqno->GetText() == 0)
+ BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<seqno> element is missing"));
+
+ state.update (info, SeqNo (
+ lexical_cast<uint32_t> (session->GetText()),
+ lexical_cast<uint32_t> (seqno->GetText())
+ ));
+ }
+ else
+ {
+ state.remove (info);
+ }
+ }
+
+ return in;
+}
+
}
diff --git a/model/sync-state.h b/model/sync-state.h
index 71e65c1..26ea5f4 100644
--- a/model/sync-state.h
+++ b/model/sync-state.h
@@ -24,6 +24,7 @@
#define SYNC_STATE_H
#include "sync-state-leaf-container.h"
+#include <boost/exception/all.hpp>
/**
* \defgroup sync SYNC protocol
@@ -68,7 +69,29 @@
LeafContainer m_leaves;
};
-std::string & operator >> (std::string &DataBuffer, State &state);
+/**
+ * @brief Formats an XML representation of the state
+ * @param os output stream
+ * @param state state
+ * @returns output stream
+ */
+std::ostream &
+operator << (std::ostream &os, const State &state);
+
+/**
+ * @brief Parses an XML representation to the state
+ * @param DataBuffer input data
+ * @param state state
+ */
+// void
+// operator >> (const std::string &DataBuffer, State &state);
+std::istream &
+operator >> (std::istream &in, State &state);
+
+/**
+ * @brief Will be thrown when XML cannot be properly decoded to State
+ */
+struct SyncXmlDecodingFailure : virtual boost::exception, virtual std::exception { };
} // Sync
diff --git a/test/test_state.cc b/test/test_state.cc
index e1a5e81..7732798 100644
--- a/test/test_state.cc
+++ b/test/test_state.cc
@@ -147,21 +147,52 @@
state.update (name2, SeqNo (12));
state.update (name3, SeqNo (8));
+ string xml1 = "<state>"
+ "<item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+ "<item><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item>"
+ "<item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+ "</state>";
{
ostringstream os;
os << state;
string s = os.str ();
erase_all (s, "\n");
- BOOST_CHECK_EQUAL (s, "<state type=\"full\"><item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item><item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+ BOOST_CHECK_EQUAL (s, xml1);
}
state.remove (name2);
+ string xml2 = "<state>"
+ "<item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+ "<item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+ "</state>";
{
ostringstream os;
os << state;
string s = os.str ();
erase_all (s, "\n");
- BOOST_CHECK_EQUAL (s, "<state type=\"full\"><item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+ BOOST_CHECK_EQUAL (s, xml2);
+ }
+
+ FullState state2;
+ istringstream xml1_is (xml1);
+ BOOST_CHECK_NO_THROW (xml1_is >> state2);
+ {
+ ostringstream os;
+ os << state2;
+ string xml1_test = os.str ();
+ erase_all (xml1_test, "\n");
+ BOOST_CHECK_EQUAL (xml1_test, xml1);
+ }
+
+ istringstream xml2_is ("<state><item action=\"remove\"><name>2</name></item></state>");
+ BOOST_CHECK_NO_THROW (xml2_is >> state2);
+
+ {
+ ostringstream os;
+ os << state2;
+ string xml2_test = os.str ();
+ erase_all (xml2_test, "\n");
+ BOOST_CHECK_EQUAL (xml2_test, xml2);
}
}
@@ -177,22 +208,58 @@
state.update (name2, SeqNo (12));
state.update (name3, SeqNo (8));
+ string xml1 = "<state>"
+ "<item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+ "<item action=\"update\"><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item>"
+ "<item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+ "</state>";
{
ostringstream os;
os << state;
- string s = os.str ();
- erase_all (s, "\n");
- BOOST_CHECK_EQUAL (s, "<state type=\"diff\"><item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item action=\"update\"><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item><item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+ string xml1_test = os.str ();
+ erase_all (xml1_test, "\n");
+ BOOST_CHECK_EQUAL (xml1_test, xml1);
}
state.remove (name2);
+ string xml2 = "<state>"
+ "<item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+ "<item action=\"remove\"><name>2</name></item>"
+ "<item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+ "</state>";
{
ostringstream os;
os << state;
- string s = os.str ();
- erase_all (s, "\n");
- BOOST_CHECK_EQUAL (s, "<state type=\"diff\"><item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item action=\"remove\"><name>2</name></item><item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+ string xml2_test = os.str ();
+ erase_all (xml2_test, "\n");
+ BOOST_CHECK_EQUAL (xml2_test, xml2);
}
+
+ //////////// //////////// //////////// //////////// //////////// ////////////
+
+ DiffState state2;
+ istringstream xml1_is (xml1);
+ BOOST_CHECK_NO_THROW (xml1_is >> state2);
+
+ {
+ ostringstream os;
+ os << state2;
+ string xml1_test = os.str ();
+ erase_all (xml1_test, "\n");
+ BOOST_CHECK_EQUAL (xml1_test, xml1);
+ }
+
+ istringstream xml2_is ("<state><item action=\"remove\"><name>2</name></item></state>");
+ BOOST_CHECK_NO_THROW (xml2_is >> state2);
+
+ {
+ ostringstream os;
+ os << state2;
+ string xml2_test = os.str ();
+ erase_all (xml2_test, "\n");
+ BOOST_CHECK_EQUAL (xml2_test, xml2);
+ }
+
}
BOOST_AUTO_TEST_SUITE_END()