// ApplicationRepository.cxx #include "dial_app/ApplicationRepository.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::ApplicationId; using dial::Application; using dial::ApplicationRepository; typedef ApplicationRepository::size_type size_type; //********************************************************************** // Local definitions. //********************************************************************** namespace { //********************************************************************** // Default repository. // First pass, use set_default_instance or define an invalid repository // if this fails. ApplicationRepository* defrep(ApplicationRepository* pnewrep =0) { static bool first = true; static ApplicationRepository* prep = 0; if ( first ) { first = false; ApplicationRepository::set_default_instance(""); if ( prep == 0 ) { prep = new ApplicationRepository; } } if ( pnewrep != 0 ) { delete prep; prep = pnewrep; } return prep; } //********************************************************************** } // end unnamed namespace //********************************************************************** // Static methods. //********************************************************************** // Return the default instance. ApplicationRepository& ApplicationRepository::default_instance() { return *defrep(); } //********************************************************************** // Set the default instance. int ApplicationRepository::set_default_instance(string name) { ApplicationRepository *prep = new ApplicationRepository(name); if ( prep->is_valid() ) { defrep(prep); } else { delete prep; return 1; } return 0; } //********************************************************************** // Create default instance. int ApplicationRepository::create_default_instance() { // Define connection resolver. ConnectionResolver::set_configuration_file("resolver.dat"); // Error if ApplicationRepository is already present. ConnectionResolver res; if ( res.resolve("ApplicationRepository", "").size() ) return 2; // Append to resolver. Text txt("resolver.dat"); txt.append("ApplicationRepository"); txt.append("SQLRESULT:" + getcwd() + "/ar.dat"); txt.write(); // Construct file description of repository. system("rm -f ar.dat"); Text tdsc("ar.dat"); tdsc.append("SQLRESULT"); tdsc.append("idhi,idlo,sxml"); tdsc.append("0,0,ApplicationRepository"); tdsc.write(); return 0; } //********************************************************************** // Private member functions. //********************************************************************** // Copy constructor. ApplicationRepository::ApplicationRepository(const ApplicationRepository&) { assert(false); } //********************************************************************** // Assignment. ApplicationRepository& ApplicationRepository::operator=(const ApplicationRepository&) { assert(false); return *this; } //********************************************************************** // Non-static methods. //********************************************************************** // Default Constructor. ApplicationRepository::ApplicationRepository() : m_prep(0) { } //********************************************************************** // Constructor from a generic repository. ApplicationRepository::ApplicationRepository(GenericRepository *prep) : m_prep(prep) { } //********************************************************************** // Constructor from connection string. ApplicationRepository::ApplicationRepository(string conn) : m_prep(GenericRepository::create("ApplicationRepository", conn)), m_manage(true) { } //********************************************************************** // Destructor. // Manage the GenericRepository only if m_manage=true ApplicationRepository::~ApplicationRepository() { if ( m_manage == true ) delete m_prep; } //********************************************************************** // Validity. bool ApplicationRepository::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 ApplicationRepository::error() const { return m_error; } //********************************************************************** // Error message. string ApplicationRepository::error_message() const { CatalogError err("application"); return err.message(m_error); } //********************************************************************** // Size. size_type ApplicationRepository::size() const { if ( ! is_valid() ) return false; return m_prep->size(); } //********************************************************************** // Return if the transient store has an application . // Otherwise check in persistent store. bool ApplicationRepository::has(ApplicationId 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 application associated with an ID from transient store. // Otherwise, return it from persistent store. const Application* ApplicationRepository::extract(ApplicationId 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 application in transient store. RepMap::iterator ids = m_dss.find(id); if ( ids != m_dss.end() ) { if ( ids->first != id ) return 0; const Application* 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 Application *pobj = new Application(*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 application in the repository. ApplicationId ApplicationRepository::insert(const Application* pds, bool manage) { if ( ! is_valid() ) return ApplicationId(); // Check input application. if ( pds == 0 ) { m_error = CatalogError::null_object_error(); return ApplicationId(); } if ( ! pds->is_valid() ) { m_error = CatalogError::invalid_object_error(); return ApplicationId(); } if ( ! pds->id().is_global() ) { m_error = CatalogError::local_id_error(); return ApplicationId(); } // Make sure the ID is not already used. ApplicationId id = pds->id(); if ( has(id) ) { m_error = CatalogError::id_assigned_error(); return ApplicationId(); } // Write the application 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 ApplicationId(); } m_dss[id] = pds; m_mgs[id] = manage; return id; } //********************************************************************** // Remove a application from repository. // Returns 0 on success. int ApplicationRepository::remove(ApplicationId 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 ApplicationRepository::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 application. 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 Application *pdb = new Application(*pxml); delete pxml; if ( pdb == 0 || ! pdb->is_valid() ) { m_error = CatalogError::object_create_error(); return false; } } return true; } //********************************************************************** // Output stream. ostream& ApplicationRepository::ostr(ostream& str) const { if ( ! is_valid() ) { str << "Invalid application repository"; return str; } size_type count = size(); str << "Application repository has " << count << " entr"; if ( count == 1 ) { str << "y"; } else { str << "ies"; } return str; } //********************************************************************** // Web page. // // Supported entries: // maxent=123 // aid=123-456 Text ApplicationRepository:: web_page(string baseurl, string entry) { // Header. Text wp; wp.append(""); bool footer = true; bool showrep = false; bool showapp = false; ApplicationId aid; 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 ==> display 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 application. } else if ( entry0.size() > 4 && entry0.substr(0,4) == "aid=" ) { string said = entry0.substr(4); aid = ApplicationId(said); if ( aid.is_valid() ) { showapp = true; } } // Show repository. if ( showrep ) { ostringstream sout; sout << *this; wp.append(sout.str()); // Show application. } else if ( showapp ) { const Application* papp = extract(aid); if ( papp == 0 ) { wp.append("Unable to find application with ID " + aid.to_string()); } else { string newbaseurl = baseurl + "?" + entry; wp = papp->web_page(newbaseurl, entryrem); footer = false; } // Error } else { wp.append("Unable resolve application entry " + entry); } // Footer. if ( footer ) wp.append(""); return wp; } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const ApplicationRepository& rhs) { return rhs.ostr(lhs); } //**********************************************************************