diff --git a/plugins/xmlsave/src/xml_serializer.cc b/plugins/xmlsave/src/xml_serializer.cc index e543d51..55089cb 100644 --- a/plugins/xmlsave/src/xml_serializer.cc +++ b/plugins/xmlsave/src/xml_serializer.cc @@ -19,29 +19,17 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "xml_serializer.hh" -#include "xml_visitor.hh" #include "xml_serializer_factory.hh" +#include "xml_visitor.hh" -#include "string_utils.hh" -#include "environment.hh" -#include "history.hh" -/* -#include "backend/concrete_environment.hh" -#include "backend/concrete_history.hh" -*/ +#include "backend/environment.hh" +#include "backend/history.hh" #include "backend/process.hh" #include "backend/serializer_error.hh" +#include "backend/string_utils.hh" using namespace sgpem; - - -#include -using namespace std; - - - - XMLSerializer::~XMLSerializer() { } @@ -81,7 +69,6 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his { // TODO - all to do!! // DEBUG - remove me when finished - XMLSerializerFactory fact(hist); #ifdef LIBXML_SAX1_ENABLED xmlDocPtr doc; @@ -97,6 +84,10 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his xmlCleanupParser(); throw SerializerError("Parsing Error: doc is invalid."); } + + clear_history(hist); + XMLSerializerFactory fact(hist); + // read all elements and fill hist read_doc(doc, fact); @@ -121,13 +112,13 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his const Glib::ustring XMLSerializer::get_filename_extension() { - return Glib::ustring("ocio"); + return Glib::ustring("xsgp"); } const Glib::ustring XMLSerializer::get_filename_description() { - return Glib::ustring("SGPEMv2 XML formatted snapshot save file"); + return Glib::ustring("SGPEMv2 XML savefile"); } void XMLSerializer::fill_doc(xmlDocPtr doc, const History& hist) @@ -142,22 +133,27 @@ void XMLSerializer::fill_doc(xmlDocPtr doc, const History& hist) /* * Creates a DTD declaration. Isn't mandatory. */ - // dtd = xmlCreateIntSubset(doc, BAD_CAST "root", NULL, BAD_CAST "tree2.dtd"); + xmlDtdPtr dtd = xmlCreateIntSubset(doc, (const xmlChar *) "sgpem", NULL, (const xmlChar *) "sgpem.dtd"); - /* - * xmlNewChild() creates a new node, which is "attached" as child node - * of root_node node. - */ + XMLVisitor xvisit(root_node); + xvisit.from_history(hist); + /* + // + // xmlNewChild() creates a new node, which is "attached" as child node + // of root_node node. + // xmlNodePtr resources_node = xmlNewChild(root_node, NULL, (const xmlChar *) "resources", NULL); - /* - * The same as above, but the new child node doesn't have a content - */ + // + // The same as above, but the new child node doesn't have a content + // xmlNodePtr schedulables_node = xmlNewChild(root_node, NULL, (const xmlChar *) "schedulables", NULL); fill_resources(resources_node, hist); fill_schedulables(schedulables_node, hist); + */ } +/* void XMLSerializer::fill_resources(xmlNodePtr resources_node, const History& hist) { @@ -197,24 +193,33 @@ void XMLSerializer::fill_schedulables(xmlNodePtr schedulables_node, const Histor iter++; } } +*/ void XMLSerializer::clear_history(History& hist) { -/* + const Environment& env = hist.get_last_environment(); const Environment::Processes& pvect = env.get_processes(); typedef std::vector::const_iterator proc_iterator; proc_iterator iter = pvect.begin(); - proc_iterator end = pvect.end(); - while(iter!=end) + while(iter!=pvect.end()) { - xvisit.from_process(*(*iter)); - pvect. + hist.remove(*(*iter)); iter = pvect.begin(); } -*/ + + const Environment::Resources& rvect = env.get_resources(); + typedef Environment::Resources::const_iterator res_iterator; + + res_iterator riter = rvect.begin(); + while(riter!=rvect.end()) + { + hist.remove((*riter).first); + riter = rvect.begin(); + } + } void XMLSerializer::read_doc(xmlDocPtr doc, XMLSerializerFactory& fact) @@ -230,14 +235,10 @@ void XMLSerializer::read_doc(xmlDocPtr doc, XMLSerializerFactory& fact) throw SerializerError("Reading Error: xml doc is empty."); } - // cout << "ROOT: " << root->name << endl; - xmlNodePtr cur; cur = root->children; while(cur!=NULL) { - // cout << "NODE: " << cur->name << endl; - Glib::ustring name((const char *)cur->name); if(name=="resources") { @@ -258,25 +259,16 @@ XMLSerializerFactory::Parameters* read_properties(xmlAttrPtr prop) XMLSerializerFactory::Parameters* par=new XMLSerializerFactory::Parameters(); while (prop != NULL) { - // // cout << "PROP: " << prop->name; - if(prop->children && xmlNodeIsText(prop->children)){ xmlChar *key = xmlNodeGetContent (prop->children); // xmlChar *key = xmlNodeListGetString(doc, prop->children, 1); if(key!=NULL) { - // // cout << " VALUE: " << key; std::pair key_value(Glib::ustring((const char *)prop->name), Glib::ustring((const char *)key)); par->insert(key_value); - // c.insert(typename Cont::value_type(new_key, pos->second)); - // cout << " pair PROP: " << key_value.first << " VALUE: " << key_value.second << endl; - xmlFree(key); } - // else - // cout << " !VALUE IS NULL! "; } - // cout << endl; prop = prop->next; } return par; @@ -291,8 +283,6 @@ void XMLSerializer::read_resources(xmlNodePtr resources_node, XMLSerializerFacto Glib::ustring node_name((const char *)cur->name); if(node_name=="resource") { - // cout << "read_resources NODE: " << cur->name << endl; - xmlAttrPtr prop = cur->properties; XMLSerializerFactory::Parameters* par=read_properties(prop); if(par!=NULL) @@ -317,8 +307,6 @@ void XMLSerializer::read_schedulables(xmlNodePtr schedulables_node, XMLSerialize Glib::ustring node_name((const char *)cur->name); if(node_name=="process") { - // cout << "read_schedulables NODE: " << cur->name << endl; - xmlAttrPtr prop = cur->properties; XMLSerializerFactory::Parameters* par=read_properties(prop); if(par!=NULL) @@ -345,8 +333,6 @@ void XMLSerializer::read_threads(xmlNodePtr threads_node, XMLSerializerFactory& Glib::ustring node_name((const char *)cur->name); if(node_name=="thread") { - // cout << "read_threads NODE: " << cur->name << endl; - xmlAttrPtr prop = cur->properties; XMLSerializerFactory::Parameters* par=read_properties(prop); if(par!=NULL) @@ -365,7 +351,6 @@ void XMLSerializer::read_requests(xmlNodePtr requests_node, XMLSerializerFactory { if(requests_node==NULL) { - // cout << "read_requests NULL" << endl; return; } @@ -376,8 +361,6 @@ void XMLSerializer::read_requests(xmlNodePtr requests_node, XMLSerializerFactory Glib::ustring node_name((const char *)cur->name); if(node_name=="request") { - // cout << "read_requests NODE: " << cur->name << endl; - xmlAttrPtr prop = cur->properties; XMLSerializerFactory::Parameters* par=read_properties(prop); if(par!=NULL) @@ -396,7 +379,6 @@ void XMLSerializer::read_subrequests(xmlNodePtr subrequest_node, XMLSerializerFa { if(subrequest_node==NULL) { - // cout << "read_subrequest NULL" << endl; return; } @@ -407,8 +389,6 @@ void XMLSerializer::read_subrequests(xmlNodePtr subrequest_node, XMLSerializerFa Glib::ustring node_name((const char *)cur->name); if(node_name=="subrequest") { - // cout << "read_subrequest NODE: " << cur->name << endl; - xmlAttrPtr prop = cur->properties; XMLSerializerFactory::Parameters* par=read_properties(prop); if(par!=NULL) diff --git a/plugins/xmlsave/src/xml_serializer.hh b/plugins/xmlsave/src/xml_serializer.hh index 79743ac..a13b954 100644 --- a/plugins/xmlsave/src/xml_serializer.hh +++ b/plugins/xmlsave/src/xml_serializer.hh @@ -25,8 +25,10 @@ #include "serializer.hh" #include -#include #include +#include + + namespace sgpem { class XMLSerializerFactory; @@ -36,28 +38,137 @@ namespace sgpem { class XMLSerializer; + /** + \brief Loads and saves from/to XML + + Serialization should be done to temporary files, which are then moved in place when serialization has finished without errors. + + See mkstemp(3). + */ class XMLSerializer : public Serializer { public: XMLSerializer(); virtual ~XMLSerializer(); + /** + Tries to open filename for writing, else throws SerializerError. + + Respecting the SGPEMv2 DTD for the snapshots, + creates a new XML document node and write to disk + using a new xmlsave::XMLVisitor. + Calls fill_doc to accomplish this task. + + \throws backend::SerializerError on error + */ virtual void save_snapshot(const Glib::ustring& filename, const History& hist); + + /** + \brief Re-initialize system status from a saved XML snapshot + + Tries to open filename for reading, else throws SerializerError. + First validates file versus the SGPEMv2 DTD for snapshots, then reads it. + Calls read_doc to relize the work. + + \throws backend::SerializerError + */ virtual void restore_snapshot(const Glib::ustring& filename, History& hist); + + /** + \return Constant string "xsgp" + */ virtual const Glib::ustring get_filename_extension(); + + /** + \return Constant string "SGPEMv2 XML savefile" + */ virtual const Glib::ustring get_filename_description(); protected: private: - void fill_doc(xmlDocPtr doc, const History& hist); - void fill_resources(xmlNodePtr resources_node, const History& hist); - void fill_schedulables(xmlNodePtr schedulables_node, const History& hist); + /** + \brief Create the document root and fill the data + Create the document root and children "resources" and "schedulables", + then calls fill_resources and fill_schedulables to fill all with data. + */ + void fill_doc(xmlDocPtr doc, const History& hist); + + /** + \brief Take a resources node and fill it with the data + + For each resource in hist create a "resource" node and fill with data. + Uses an XMLVisitor object to do the task. + */ + // void fill_resources(xmlNodePtr resources_node, const History& hist); + + /** + \brief Take a schedulables node and fill it with the data + + For each resource in hist create a "schedulable" node and fill with data. + Also all schedulable sub nodes are generated too. + Uses an XMLVisitor object to do the task. + */ + // void fill_schedulables(xmlNodePtr schedulables_node, const History& hist); + + /** + \brief Clear the passed history + + For each process in history deletes it. + For each resource in history deletes it. + */ void clear_history(History& hist); + + /** + \brief Restore the snapshot from the passed xml document + + Traverse the passed (previously readed) xml document and + rebuild the correct image using the XMLSerializerFactory object. + */ void read_doc(xmlDocPtr doc, XMLSerializerFactory& fact); + + /** + \brief Restore all the resources from the passed xml node + + Traverse the passed (previously readed) xml node and + rebuild the correct resources image using the XMLSerializerFactory + object. + */ void read_resources(xmlNodePtr resources_node, XMLSerializerFactory& fact); + + /** + \brief Restore all the schedulables (processes) from the passed xml node + + Traverse the passed (previously readed) xml node and + rebuild the correct processes (and sub objects) images using the + XMLSerializerFactory object. + */ void read_schedulables(xmlNodePtr schedulables_node, XMLSerializerFactory& fact); + + /** + \brief Restore all threads from the passed xml node + + Traverse the passed (previously readed) xml node and + rebuild the correct threads (and sub objects) images using the + XMLSerializerFactory object. + */ void read_threads(xmlNodePtr schedulables_node, XMLSerializerFactory& fact); + + /** + \brief Restore all the requests from the passed xml node + + Traverse the passed (previously readed) xml node and + rebuild the correct requests (and sub objects) images using the + XMLSerializerFactory object. + */ void read_requests(xmlNodePtr schedulables_node, XMLSerializerFactory& fact); + + /** + \brief Restore all the subrequests from the passed xml node + + Traverse the passed (previously readed) xml node and + rebuild the correct subrequests image using the + XMLSerializerFactory object. + */ void read_subrequests(xmlNodePtr schedulables_node, XMLSerializerFactory& fact); }; } diff --git a/plugins/xmlsave/src/xml_serializer_factory.cc b/plugins/xmlsave/src/xml_serializer_factory.cc index b076372..3ca45ac 100644 --- a/plugins/xmlsave/src/xml_serializer_factory.cc +++ b/plugins/xmlsave/src/xml_serializer_factory.cc @@ -187,7 +187,7 @@ XMLSerializerFactory::create_thread(Parameters& parameters) } // read "arrival-time" property - pos = parameters.find(Glib::ustring("arrival-time")); + pos = parameters.find(Glib::ustring("arrival-delta")); if (pos != parameters.end()) { string_to_int(pos->second, arrival_time); } diff --git a/plugins/xmlsave/src/xml_serializer_factory.hh b/plugins/xmlsave/src/xml_serializer_factory.hh index 5928b61..9dc16b6 100644 --- a/plugins/xmlsave/src/xml_serializer_factory.hh +++ b/plugins/xmlsave/src/xml_serializer_factory.hh @@ -41,32 +41,72 @@ namespace sgpem namespace sgpem { class XMLSerializerFactory; - + /** + \brief Creates objects given their class name and an array of their properties + + Resources should come first in deserialization, so save pointers to new objects to a backend::Resource into a std::map. This will come really handy when deserializing Requests. + */ class XMLSerializerFactory { public: + typedef std::map Parameters; + + /** + \brief Contructor takes an history as readed data destination + */ XMLSerializerFactory(History& hist); + + /** + \brief A destructor, nothing else + */ ~XMLSerializerFactory(); + /** + \return The data destination history associated with this factory + */ History* get_history(); - typedef Environment::resource_key_t resource_key_t; - // typedef const std::pair ResourcePair; - //NOUSE typedef const std::map Parameters; - // associate old keys with new ones - typedef std::map Parameters; - - // associate old keys with new ones - //typedef pair TempPair; - typedef std::map TempMap; + /** + \brief Creates objects from their name plus parameters + + This method recognizes a class type and calls the appropriate + creator method, which must also take care of inserting the + new object in its right container, if necessary. + + \throw SerializerError If not all necessary parameters for an object creation are provided + */ void factory_method(const Glib::ustring& class_name, Parameters& parameters); protected: private: + typedef Environment::resource_key_t resource_key_t; + // associate old keys with new ones + typedef std::map TempMap; + + /** + Resource factory from given parameters + */ History::ResourcePair create_resource(Parameters& parameters); + + /** + Process factory from given parameters + */ Process& create_process(Parameters& parameters); + + /** + Thread factory from given parameters + */ Thread& create_thread(Parameters& parameters); + + /** + Request factory from given parameters + */ Request& create_request(Parameters& parameters); + + /** + \throw A SerializerError if there's no existing associated resource + for a given ID parameter (it means the savefile is corrupted). + */ SubRequest& create_subrequest(Parameters& parameters); // history object to add to resources processes etc... diff --git a/plugins/xmlsave/src/xml_visitor.cc b/plugins/xmlsave/src/xml_visitor.cc index 4883047..a6933b5 100644 --- a/plugins/xmlsave/src/xml_visitor.cc +++ b/plugins/xmlsave/src/xml_visitor.cc @@ -20,25 +20,20 @@ #include "xml_visitor.hh" -#include "string_utils.hh" -#include "resource.hh" +#include "gettext.h" + +#include "environment.hh" +#include "history.hh" #include "process.hh" -#include "thread.hh" #include "request.hh" -#include "sub_request.hh" +#include "resource.hh" #include "serializer_error.hh" - -#include -using namespace std; - +#include "string_utils.hh" +#include "sub_request.hh" +#include "thread.hh" using namespace sgpem; -/* -#include -using namespace std; -*/ - XMLVisitor::XMLVisitor(xmlNodePtr current) : _current(current) @@ -51,6 +46,21 @@ XMLVisitor::~XMLVisitor() void XMLVisitor::from_resource(const Resource& obj) { + throw SerializerError( + _("XMLVisitor: unsupported method from_resource(const Resource& obj)") + ); +} + + +void XMLVisitor::from_history(const History& obj) +{ + from_history(_current, obj); +} + + +void XMLVisitor::from_environment(const Environment& obj) +{ + from_environment(_current, obj); } @@ -68,11 +78,13 @@ void XMLVisitor::from_thread(const Thread& obj) void XMLVisitor::from_request(const Request& obj) { + from_request(_current, obj); } void XMLVisitor::from_subrequest(const SubRequest& obj) { + from_subrequest(_current, obj); } void XMLVisitor::from_resource(const Resource& obj, const Glib::ustring& key) @@ -85,11 +97,66 @@ void XMLVisitor::from_resource(const Resource& obj, const Glib::ustring& key) -/* -void XMLVisitor::from_resource(xmlNodePtr parent, const Resource& obj) + +void XMLVisitor::from_history(xmlNodePtr parent, const History& hist) { + if(parent!=NULL) + { + from_environment(parent, hist.get_last_environment()); + } + else + { + throw SerializerError(_("Error trying to add data to empty XML node.")); + } } -*/ + + +void XMLVisitor::from_environment(xmlNodePtr parent, const Environment& env) +{ + if(parent==NULL) + { + throw SerializerError(_("Error trying to add data to empty XML node.")); + } + // + //Enclosing block - save resources + // + { + xmlNodePtr resources_node = xmlNewChild(parent, NULL, (const xmlChar *) "resources", NULL); + const Environment::Resources& rvect = env.get_resources(); + typedef Environment::Resources::const_iterator res_iterator; + + res_iterator iter = rvect.begin(); + res_iterator end = rvect.end(); + while(iter!=end) + { + //XMLVisitor xvisit(resources_node); + Glib::ustring key; + int_to_string((int)(*iter).first, key); + //xvisit.from_resource(*((*iter).second), key); + from_resource(resources_node, *((*iter).second), key); + iter++; + } + } + // + //Enclosing block - save schedulables + // + { + xmlNodePtr schedulables_node = xmlNewChild(parent, NULL, (const xmlChar *) "schedulables", NULL); + const Environment::Processes& pvect = env.get_processes(); + typedef std::vector::const_iterator proc_iterator; + + proc_iterator iter = pvect.begin(); + proc_iterator end = pvect.end(); + while(iter!=end) + { + // XMLVisitor xvisit(schedulables_node); + // xvisit.from_process(*(*iter)); + from_process(schedulables_node, *(*iter)); + iter++; + } + } +} + void XMLVisitor::from_resource(xmlNodePtr parent, const Resource& obj, const Glib::ustring& key) { @@ -109,7 +176,7 @@ void XMLVisitor::from_resource(xmlNodePtr parent, const Resource& obj, const Gli } else { - throw SerializerError("Error trying to add resource to empty XML node."); + throw SerializerError(_("Error trying to add resource to empty XML node.")); } } @@ -131,7 +198,6 @@ void XMLVisitor::from_process(xmlNodePtr parent, const Process& obj) // make a threads subnode xmlNodePtr threads_node = xmlNewChild(process_node, NULL, (const xmlChar *) "threads", NULL); - // cout << "PROCESS: " << obj.get_name() << endl; // iterate on threads typedef std::vector Threads; typedef std::vector::const_iterator thr_iterator; @@ -141,7 +207,6 @@ void XMLVisitor::from_process(xmlNodePtr parent, const Process& obj) while(iter!=end) { const Thread* t = *iter; - // cout << "THREAD: " << t->get_name() << endl; from_thread(threads_node, *(*iter)); iter++; @@ -149,7 +214,7 @@ void XMLVisitor::from_process(xmlNodePtr parent, const Process& obj) } else { - throw SerializerError("Error trying to add process to empty XML node."); + throw SerializerError(_("Error trying to add process to empty XML node.")); } } @@ -174,7 +239,6 @@ void XMLVisitor::from_thread(xmlNodePtr parent, const Thread& obj) // make a requests subnode xmlNodePtr requests_node = xmlNewChild(thread_node, NULL, (const xmlChar *) "requests", NULL); - // cout << "PROCESS: " << obj.get_name() << endl; // iterate on requests typedef std::vector Requests; typedef std::vector::const_iterator req_iterator; @@ -184,7 +248,6 @@ void XMLVisitor::from_thread(xmlNodePtr parent, const Thread& obj) while(iter!=end) { const Request* r = *iter; - // cout << "REQUEST: " << r->get_instant() << endl; from_request(requests_node, *(*iter)); iter++; @@ -192,7 +255,7 @@ void XMLVisitor::from_thread(xmlNodePtr parent, const Thread& obj) } else { - throw SerializerError("Error trying to add thread to empty XML node."); + throw SerializerError(_("Error trying to add thread to empty XML node.")); } } @@ -210,7 +273,6 @@ void XMLVisitor::from_request(xmlNodePtr parent, const Request& obj) // make a requests subnode // xmlNodePtr subrequests_node = xmlNewChild(thread_node, NULL, (const xmlChar *) "requests", NULL); - // cout << "PROCESS: " << obj.get_name() << endl; // iterate on subrequests typedef std::vector SubRequests; typedef std::vector::const_iterator subreq_iterator; @@ -220,14 +282,13 @@ void XMLVisitor::from_request(xmlNodePtr parent, const Request& obj) while(iter!=end) { const SubRequest* sr = *iter; - // cout << "SUB REQUEST: " << sr->get_resource_key() << " places: " << sr->get_places() << " length: " << sr->get_length() << endl; from_subrequest(request_node, *(*iter)); iter++; } } else { - throw SerializerError("Error trying to add request to empty XML node."); + throw SerializerError(_("Error trying to add request to empty XML node.")); } } @@ -251,6 +312,6 @@ void XMLVisitor::from_subrequest(xmlNodePtr parent, const SubRequest& obj) } else { - throw SerializerError("Error trying to add subrequest to empty XML node."); + throw SerializerError(_("Error trying to add subrequest to empty XML node.")); } } diff --git a/plugins/xmlsave/src/xml_visitor.hh b/plugins/xmlsave/src/xml_visitor.hh index f4635fc..42430e5 100644 --- a/plugins/xmlsave/src/xml_visitor.hh +++ b/plugins/xmlsave/src/xml_visitor.hh @@ -31,7 +31,7 @@ namespace sgpem } #include "config.h" -#include "serializer_visitor.hh" +#include "serialize_visitor.hh" #include #include @@ -41,20 +41,84 @@ namespace sgpem { class XMLVisitor; - class XMLVisitor : public SerializerVisitor + /** + \brief Serialize objects to XML + + This class is a concrete class derived from SerializeVisitor + and implements each methodto serialize + into an xml tree. + The pointer to the sgpem (root) node must be passed as constructor parameter. + */ + class XMLVisitor : public SerializeVisitor { public: + /** + \brief Class constructor to save to the passed XML tree + + Build an XMLVisitor taking a pointer to an xml node as parameter. + Every called method see this node as his relative root. + */ XMLVisitor(xmlNodePtr current); + + /** + \brief A pretty virtual destructor + */ virtual ~XMLVisitor(); + /** + \brief Add output to the serializer taking data from history + Wrapper method: call from_history(xmlNodePtr parent, const History& obj); + */ + virtual void from_history(const History& obj); + + /** + \brief Add output to the serializer taking data from environment + Wrapper method: call from_environment(xmlNodePtr parent, const Environment& obj); + */ + virtual void from_environment(const Environment& obj); + + /** + \brief Add output to the serializer taking data from resource + BUG: a resource must be saved with her own associated key. + Throw an exception. + */ virtual void from_resource(const Resource& obj); + + /** + \brief Add output to the serializer taking data from resource and key + BUG FIXED: This save a resource with her own associated key. + Wrapper method: call from_resource(xmlNodePtr parent, const Resource& obj, const Glib::ustring& key); + */ + virtual void from_resource(const Resource& obj, const Glib::ustring& key); + + /** + \brief Add output to the serializer taking data from process + Wrapper method: call from_process(xmlNodePtr parent, const Process& obj); + */ virtual void from_process(const Process& obj); + + /** + \brief Add output to the serializer taking data from thread + Wrapper method: call from_thread(xmlNodePtr parent, const Thread& obj); + */ virtual void from_thread(const Thread& obj); + + /** + \brief Add output to the serializer taking data from request + Wrapper method: call from_request(xmlNodePtr parent, const Request& obj); + */ virtual void from_request(const Request& obj); + + /** + \brief Add output to the serializer taking data from subrequest + Wrapper method: call from_subrequest(xmlNodePtr parent, const SubRequest& obj); + */ virtual void from_subrequest(const SubRequest& obj); - virtual void from_resource(const Resource& obj, const Glib::ustring& key); + private: + void from_history(xmlNodePtr parent, const History& obj); + void from_environment(xmlNodePtr parent, const Environment& obj); void from_resource(xmlNodePtr parent, const Resource& obj, const Glib::ustring& key); void from_process(xmlNodePtr parent, const Process& obj); void from_thread(xmlNodePtr parent, const Thread& obj);