// TaskRepository.cxx #include "dial_task/TaskRepository.h" #include #include #include #include #include "dataset_util/getcwd.h" #include "dataset_util/XmlElement.h" #include "dataset_xml/XmlParser.h" #include "dataset_catalog/SqlGenericRepository.h" #include "dataset_catalog/ConnectionResolver.h" using std::string; using std::cout; using std::endl; using std::ostream; using std::istringstream; using std::ostringstream; using std::auto_ptr; using dset::SqlTable; using dset::GenericRepository; using dset::SqlGenericRepository; using dset::ConnectionResolver; using dset::CatalogError; using dial::TaskId; using dial::Task; using dial::TaskRepository; typedef TaskRepository::size_type size_type; //********************************************************************** // Local definitions. //********************************************************************** namespace { //********************************************************************** // Default repository. // First pass, use set_default_instance or define an invalid repository // if this fails. TaskRepository* defrep(TaskRepository* pnewrep =0) { static bool first = true; static TaskRepository* prep = 0; if ( first ) { first = false; TaskRepository::set_default_instance(""); if ( prep == 0 ) { prep = new TaskRepository; } } if ( pnewrep != 0 ) { delete prep; prep = pnewrep; } return prep; } //********************************************************************** } // end unnamed namespace //********************************************************************** // Static methods. //********************************************************************** // Return the default instance. TaskRepository& TaskRepository::default_instance() { return *defrep(); } //********************************************************************** // Set the default instance. int TaskRepository::set_default_instance(string name) { TaskRepository *prep = new TaskRepository(name); if ( prep->is_valid() ) { defrep(prep); } else { delete prep; return 1; } return 0; } //********************************************************************** // Create default instance. int TaskRepository::create_default_instance() { // Define connection resolver. ConnectionResolver::set_configuration_file("resolver.dat"); // Error if TaskRepository is already present. ConnectionResolver res; if ( res.resolve("TaskRepository", "").size() ) return 2; // Append to resolver. Text txt("resolver.dat"); txt.append("TaskRepository"); txt.append("SQLRESULT:" + getcwd() + "/tr.dat"); txt.write(); // Construct file description of repository. system("rm -f tr.dat"); Text tdsc("tr.dat"); tdsc.append("SQLRESULT"); tdsc.append("idhi,idlo,sxml"); tdsc.append("0,0,TaskRepository"); tdsc.write(); return 0; } //********************************************************************** // Private member functions. //********************************************************************** // Copy constructor. TaskRepository::TaskRepository(const TaskRepository&) { assert(false); } //********************************************************************** // Assignment. TaskRepository& TaskRepository::operator=(const TaskRepository&) { assert(false); return *this; } //********************************************************************** // Non-static methods. //********************************************************************** // Default Constructor. TaskRepository::TaskRepository() : m_prep(0) { } //********************************************************************** // Constructor from a generic repository. TaskRepository::TaskRepository(GenericRepository *prep) : m_prep(prep) { } //********************************************************************** // Constructor from connection string. TaskRepository::TaskRepository(string conn) : m_prep(GenericRepository::create("TaskRepository", conn)), m_manage(true) { } //********************************************************************** // Destructor. // Manage the GenericRepository only if m_manage=true TaskRepository::~TaskRepository() { if ( m_manage == true ) delete m_prep; } //********************************************************************** // Validity. bool TaskRepository::is_valid() const { m_error = CatalogError::no_error(); if ( m_prep == 0 || ! m_prep->is_valid() ) { m_error = CatalogError::generic_access_error(); return false; } return true; } //********************************************************************** // Error code. int TaskRepository::error() const { return m_error; } //********************************************************************** // Error message. string TaskRepository::error_message() const { CatalogError err("task"); return err.message(m_error); } //********************************************************************** // Size. size_type TaskRepository::size() const { if ( ! is_valid() ) return false; return m_prep->size(); } //********************************************************************** // Return if the transient store has a task. // Otherwise check in persistent store. bool TaskRepository::has(TaskId id) const { if ( ! is_valid() ) return false; // Exit if input ID is invalid. if ( ! id.is_valid() ) { m_error = CatalogError::invalid_id_error(); return false; } if ( ! id.is_global() ) { m_error = CatalogError::local_id_error(); return false; } // Transient store. RepMap::const_iterator ids = m_dss.find(id); if ( ids != m_dss.end() ) return true; // Persistent store. return m_prep->has(id.to_string()); } //********************************************************************** // Return the task associated with an ID from transient store. // Otherwise, return it from persistent store. const Task* TaskRepository::extract(TaskId id, bool readnull) { if ( ! is_valid() ) return 0; // Exit if input ID is invalid. if ( ! id.is_valid() ) { m_error = CatalogError::invalid_id_error(); return 0; } if ( ! id.is_global() ) { m_error = CatalogError::local_id_error(); return 0; } // Locate task in transient store. RepMap::iterator ids = m_dss.find(id); if ( ids != m_dss.end() ) { if ( ids->first != id ) return 0; const Task* pds = ids->second; // If null and readnull is set, then delete the entry and read. if ( pds == 0 ) { m_error = CatalogError::null_object_error(); if ( readnull ) { m_dss.erase(ids); ManageMap::iterator img = m_mgs.find(id); if ( img == m_mgs.end() ) return 0; m_mgs.erase(img); } else { return 0; } } else { return pds; } } // If absent or null with readnull set, try persistent store. string sxml = m_prep->get(id.to_string()); if ( sxml == "" ) { m_error = CatalogError::no_such_object_error(); return 0; } Text::xml_to_text(sxml); XmlParser par; const XmlElement *pxml = par.parse(sxml); if ( pxml == 0 || ! pxml->is_valid() ) { m_error = CatalogError::object_parse_error(); delete pxml; return 0; } const Task *pobj = new Task(*pxml); delete pxml; if ( pobj == 0 || ! pobj->is_valid() ) { m_error = CatalogError::object_create_error(); return 0; } m_dss[id] = pobj; m_mgs[id] = true; return pobj; } //********************************************************************** // Put a task in the repository. TaskId TaskRepository::insert(const Task* pds, bool manage) { if ( ! is_valid() ) return TaskId(); // Check input task. if ( pds == 0 ) { m_error = CatalogError::null_object_error(); return TaskId(); } if ( ! pds->is_valid() ) { m_error = CatalogError::invalid_object_error(); return TaskId(); } if ( ! pds->id().is_global() ) { m_error = CatalogError::local_id_error(); return TaskId(); } // Make sure the ID is not already used. TaskId id = pds->id(); if ( has(id) ) { m_error = CatalogError::id_assigned_error(); return TaskId(); } // Write the task to persistent store. auto_ptr pele(pds->xml()); int stat = m_prep->insert(id.to_string(), pele->to_xml_text("NOCR")); if ( stat ) { m_error = CatalogError::generic_write_error(); return TaskId(); } m_dss[id] = pds; m_mgs[id] = manage; return id; } //********************************************************************** // Remove a task from repository. // Returns 0 on success. int TaskRepository::remove(TaskId id) { if ( ! is_valid() ) return 1; if ( ! id.is_valid() ) { m_error = CatalogError::invalid_id_error(); return m_error; } if ( ! id.is_global() ) { m_error = CatalogError::local_id_error(); return m_error; } int stat = m_prep->remove(id.to_string()); if ( stat != 0 ) m_error = CatalogError::generic_write_error(); m_dss.erase(id); m_mgs.erase(id); return stat; } //********************************************************************** // Verify all entries. bool TaskRepository::verify() const { // Exit if repository is invalid if ( ! is_valid() ) return false; XmlParser par; GenericRepository::IdList idl = m_prep->get_ids(); for( GenericRepository::IdList::const_iterator it = idl.begin(); it != idl.end(); ++it) { string sxml = m_prep->get(*it); Text::xml_to_text(sxml); // Entry with ID "0-0" is used to identify type of repository. // Do not verify that it has a valid task. if ( (*it) == "0-0" ) continue; const XmlElement *pxml = par.parse(sxml); if ( pxml == 0 || ! pxml->is_valid() ) { m_error = CatalogError::object_parse_error(); delete pxml; return false; } const Task *pdb = new Task(*pxml); delete pxml; if ( pdb == 0 || ! pdb->is_valid() ) { m_error = CatalogError::object_create_error(); return false; } } return true; } //********************************************************************** // Output stream. ostream& TaskRepository::ostr(ostream& str) const { if ( ! is_valid() ) { str << "Invalid task repository"; return str; } size_type count = size(); str << "Task repository has " << count << " entr"; if ( count == 1 ) { str << "y"; } else { str << "ies"; } return str; } //********************************************************************** // Web page. // // Supported entries: // maxent=123 // tid=123-456 Text TaskRepository:: web_page(string baseurl, string entry) { // Header. Text wp; wp.append(""); bool footer = true; bool showrep = false; bool showapp = false; TaskId id; int maxent = 100; // Split entry into first and remaining sub entries. string::size_type ipos = entry.find('?'); string entry0 = entry; string entryrem; if ( ipos != string::npos ) { entry0 = entry.substr(0, ipos); entryrem = entry.substr(ipos+1); } // Parse the first entry to determine the action to take. // No entry ==> dispaly table. if ( entry.size() == 0 ) { showrep = true; // maxent ==> display table. } else if ( entry0.size() > 7 && entry0.substr(0,7) == "maxent=" ) { Text::WordList words = Text::split(entry0, "="); if ( words.size() == 2 ) { string name = words[0]; string value = words[1]; // Display repository with explicit maxent. if ( name == "maxent" ) { istringstream ssvalue(value); ssvalue >> maxent; showrep = true; } } // Display task. } else if ( entry0.size() > 4 && entry0.substr(0,4) == "tid=" ) { string sid = entry0.substr(4); id = TaskId(sid); if ( id.is_valid() ) { showapp = true; } } // Show repository. if ( showrep ) { ostringstream sout; sout << *this; wp.append(sout.str()); // Show task. } else if ( showapp ) { const Task* pobj = extract(id); if ( pobj == 0 ) { wp.append("Unable to find task with ID " + id.to_string()); } else { string newbaseurl = baseurl + "?" + entry; wp = pobj->web_page(newbaseurl, entryrem); footer = false; } // Error } else { wp.append("Unable resolve task entry " + entry); } // Footer. if ( footer ) wp.append(""); return wp; } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const TaskRepository& rhs) { return rhs.ostr(lhs); } //**********************************************************************