summaryrefslogtreecommitdiff
path: root/TAO/CIAO/DAnCE/spec_RepositoryManager/RepositoryManager_Impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/CIAO/DAnCE/spec_RepositoryManager/RepositoryManager_Impl.cpp')
-rw-r--r--TAO/CIAO/DAnCE/spec_RepositoryManager/RepositoryManager_Impl.cpp705
1 files changed, 705 insertions, 0 deletions
diff --git a/TAO/CIAO/DAnCE/spec_RepositoryManager/RepositoryManager_Impl.cpp b/TAO/CIAO/DAnCE/spec_RepositoryManager/RepositoryManager_Impl.cpp
new file mode 100644
index 00000000000..d6b66dfe33c
--- /dev/null
+++ b/TAO/CIAO/DAnCE/spec_RepositoryManager/RepositoryManager_Impl.cpp
@@ -0,0 +1,705 @@
+// $Id$
+
+///====================================================================
+// filename: RepositoryManager_Impl.cpp
+// Author: Stoyan Paunov spaunov@isis.vanderbilt.edu
+//
+
+#include "RepositoryManager_Impl.h"
+
+#include "ace/OS_NS_fcntl.h" //for open
+#include "ace/OS_NS_unistd.h" //for close
+#include "ace/OS_NS_sys_stat.h" //for filesize and fstat and mkdir
+#include "ace/OS_NS_string.h" //for ACE_CString
+
+
+//to remove a file or dir from the local filesystem need remove () from stdio.h
+// ---> need to include ace/OS_NS_stdio.h which would include the correct file for any OS!
+#include "ace/OS_NS_stdio.h"
+
+#include "ZIP_Wrapper.h" //Wrapper around zzip
+#include "ace/Containers_T.h" //for ACE_Double_Linked_List
+#include "ace/Malloc_Allocator.h" //for ACE_New_Allocator needed by the doubly link list
+
+//for the PackageConfiguration parsing
+#include "Config_Handlers/STD_PC_Intf.h"
+//#include "Config_Handlers/Deployment.hpp"
+#include "ciao/Deployment_DataC.h"
+#include "ciao/Packaging_DataC.h"
+#include "Config_Handlers/Utils/XML_Helper.h"
+#include "xercesc/dom/DOM.hpp"
+
+#include "RM_Helper.h" //to be able to externalize/internalize a PackageConfiguration
+#include "ace/Message_Block.h" //for ACE_Message_Block
+
+#include "ace/Thread.h" //for obtaining the ID of the current thread
+#include "ace/OS_NS_stdlib.h" //for itoa ()
+
+#include "URL_Parser.h" //for parsing the URL
+#include "HTTP_Client.h" //the HTTP client class to downloading packages
+
+#include "PC_Updater.h" //A visitor class to walk through the elements of the PC
+
+#include <iostream>
+using namespace std;
+
+
+// Implementation skeleton constructor
+CIAO_RepositoryManagerDaemon_i::CIAO_RepositoryManagerDaemon_i (CORBA::ORB_ptr the_orb, const char* server)
+ : the_orb_ (CORBA::ORB::_duplicate (the_orb)),
+ install_root_ (""),
+ HTTP_server_ (server)
+{
+ //create directory in which the packages will be stored
+
+ ACE_OS::mkdir(INSTALL_PATH);
+ //if dir already exists a -1 is returned
+ //we ignore this, just need to make sure the directory exists
+
+ ACE_OS::getcwd (this->cwd_, TEMP_LEN);
+
+ this->install_root_ = this->cwd_;
+ this->install_root_ += "/";
+ this->install_root_ += INSTALL_PATH;
+}
+
+// Implementation skeleton destructor
+CIAO_RepositoryManagerDaemon_i::~CIAO_RepositoryManagerDaemon_i (void)
+{
+ this->names_.unbind_all ();
+ this->uuids_.unbind_all ();
+}
+
+void CIAO_RepositoryManagerDaemon_i::shutdown (
+
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException
+ ))
+{
+ // Add your implementation here
+ this->names_.unbind_all ();
+ this->uuids_.unbind_all ();
+
+ this->the_orb_->shutdown (0);
+}
+
+
+void CIAO_RepositoryManagerDaemon_i::installPackage (
+ const char * installationName,
+ const char * location
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ ::Deployment::NameExists,
+ ::Deployment::PackageError
+ ))
+{
+ // Add your implementation here
+
+ ACE_Hash_Map_Entry <ACE_CString, ACE_CString> *entry;
+
+ if (this->names_.find (ACE_CString (installationName), entry) == 0)
+ ACE_THROW (Deployment::NameExists ());
+
+ //Now lets form the path for the local file
+ //NOTE: I need the absolute path because I will change to a subdirectory
+ //when I am parsing the descriptors
+
+ ACE_CString path (this->install_root_);
+ path += "/";
+ path += installationName;
+
+ ACE_CString package_path (path);
+ package_path += ".cpk"; //package extension
+
+ ACE_CString pc_path (path);
+ pc_path += PC_EXTENSION; //external PackageConfiguration extension
+
+
+ ACE_CString descriptor_dir (path);
+ descriptor_dir += "/descriptors/"; //location of the descriptor directory
+
+
+ //check if URL or local file
+ //download or load into memory
+
+ size_t length = 0;
+
+ if (ACE_OS::strstr (location, "http://"))
+ {
+ URL_Parser *parser = URL_Parser::instance ();
+ if (!parser->parseURL (const_cast <char*> (location)))
+ ACE_THROW (CORBA::INTERNAL ());
+
+ // Create a client
+ HTTP_Client client;
+
+ //TODO: how can I incorporate a Auto_Ptr is explicit release is needed
+ ACE_Message_Block* mb = new ACE_Message_Block (0,0);
+
+ // Open the client
+ if (client.open (parser->filename_,
+ parser->hostname_,
+ parser->port_) == -1)
+ {
+ mb->release ();
+ client.close ();
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ // Read from it
+ if (client.read (mb) <= 0)
+ {
+ mb->release ();
+ client.close ();
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ // Write file to designated location on disk
+ if (!RM_Helper::write_to_disk (package_path.c_str (), *mb))
+ {
+ mb->release ();
+ client.close ();
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ mb->release ();
+ client.close ();
+ }
+ else
+ {
+ CORBA::Octet* file = 0;
+
+ //read the package from disk and store in the RM directory
+ //see if you can substiture this with a memory mapped file
+ //for better perofrmance (mimic zero copy here)
+ file = RM_Helper::read_from_disk (location, length);
+
+ if (!file)
+ ACE_THROW (CORBA::INTERNAL ());
+
+ //Store the package in the local RM dir for future retrieval
+ if (!RM_Helper::write_to_disk (package_path.c_str (), file, length))
+ ACE_THROW (CORBA::INTERNAL ());
+
+ //NOTE: MEMORY LEAK UNLESS delete file; change to Auto_Ptr
+ delete file;
+ }
+
+
+ ZIP_Wrapper::uncompress (const_cast<char*> (package_path.c_str ()),
+ const_cast<char*> (this->install_root_.c_str ()),
+ false //not verbose
+ );
+
+ //Start the parsing
+
+ ACE_CString pc_name;
+
+ this->find_PC_name (const_cast<char*> (package_path.c_str ()), pc_name);
+
+ //if the PackageConfiguration name cannot be found, then there is nothing to install
+ if (pc_name == "")
+ ACE_THROW (Deployment::PackageError ());
+
+
+ //TODO: move exception throwing out of this func. User boolean error handling!!!
+ //TODO: check for errors!
+ Deployment::PackageConfiguration_var pc;
+ pc = this->retrieve_PC_from_descriptors (const_cast<char*> (pc_name.c_str ()),
+ descriptor_dir.c_str ());
+
+
+ //forming the server path info
+ ACE_CString server_path (this->HTTP_server_);
+ server_path += installationName;
+ server_path += "/implementations/";
+
+ PC_Updater updater (server_path, package_path);
+
+ if (!updater.update (pc))
+ {
+ cout << "[RM] problem updating the PackageConfiguration!\n";
+ remove_extracted_package (package_path.c_str (), path.c_str ());
+ remove (package_path.c_str ());
+ ACE_THROW (Deployment::PackageError ());
+ }
+
+
+ //now lets externalize the PackageConfiguration, so that we can access it later on
+ //without having to do the whole parsing again.
+ //NOTE: Order here is important. Do not populate maps before the externalization!
+ RM_Helper::externalize (pc, pc_path.c_str ());
+
+ //insert the package into the database
+ this->names_.bind (ACE_CString (installationName), path);
+
+ //ALSO NEED THE UUID here
+ this->uuids_.bind (ACE_CString (pc->UUID), path);
+
+ ACE_TRACE (("Installed PackageConfiguration with: \nlabel %s \nuuid %s\n", pc->label, pc->UUID));
+}
+
+void CIAO_RepositoryManagerDaemon_i::createPackage (
+ const char * installationName,
+ const ::Deployment::PackageConfiguration & package,
+ const char * baseLocation,
+ ::CORBA::Boolean replace
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ ::Deployment::NameExists,
+ ::Deployment::PackageError
+ ))
+{
+ // Add your implementation here
+ ACE_THROW (CORBA::NO_IMPLEMENT ());
+}
+
+::Deployment::PackageConfiguration * CIAO_RepositoryManagerDaemon_i::findPackageByName (
+ const char * name
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ ::Deployment::NoSuchName
+ ))
+{
+ // Find out if the PackageConfiguration was installed in the repository,
+ // return it if found or throw and exception otherwise
+
+ ACE_Hash_Map_Entry <ACE_CString, ACE_CString> *entry = 0;
+
+ if (this->names_.find (ACE_CString (name), entry) != 0)
+ ACE_THROW (Deployment::NoSuchName ());
+ //PackageConfiguration was not found
+
+ ACE_CString pc_path (entry->int_id_.c_str ());
+ pc_path += PC_EXTENSION;
+
+ Deployment::PackageConfiguration_var pc = new Deployment::PackageConfiguration ();
+
+ if(!RM_Helper::reincarnate (pc, pc_path.c_str ()))
+ ACE_THROW_RETURN (CORBA::INTERNAL (), 0);
+
+ //maybe I will still retrieve it in the case of failure: TODO
+ //Deployment::PackageConfiguration_var pc = retrieve_PC(const_cast<char*> ());
+
+ return pc._retn ();
+}
+
+::Deployment::PackageConfiguration * CIAO_RepositoryManagerDaemon_i::findPackageByUUID (
+ const char * UUID
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ ::Deployment::NoSuchName
+ ))
+{
+ // Add your implementation here
+
+ //NOTE: The following code actually works but I have not gotten
+ //the DELETE to remove the UUIDs and I am not allowing this code
+ //to be used for right now because the RM stays in an inconsistent
+ //state. A package can be deleted but it is still retrievable by is UUID.
+ ACE_THROW_RETURN (CORBA::NO_IMPLEMENT (), 0);
+
+
+ // Find out if the PackageConfiguration was installed in the repository,
+ // return it if found or throw and exception otherwise
+
+ ACE_Hash_Map_Entry <ACE_CString, ACE_CString> *entry = 0;
+
+ if (this->uuids_.find (ACE_CString (UUID), entry) != 0)
+ ACE_THROW (Deployment::NoSuchName ());
+ //PackageConfiguration was not found
+
+ ACE_CString pc_path (entry->int_id_.c_str ());
+ pc_path += PC_EXTENSION;
+
+ Deployment::PackageConfiguration_var pc = new Deployment::PackageConfiguration ();
+
+ if(!RM_Helper::reincarnate (pc, pc_path.c_str ()))
+ ACE_THROW_RETURN (CORBA::INTERNAL (), 0);
+
+ //maybe I will still retrieve it in the case of failure: TODO
+ //Deployment::PackageConfiguration_var pc = retrieve_PC(const_cast<char*> ());
+
+ return pc._retn ();
+}
+
+::CORBA::StringSeq * CIAO_RepositoryManagerDaemon_i::findNamesByType (
+ const char * type
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException
+ ))
+{
+ // Add your implementation here
+ ACE_THROW_RETURN (CORBA::NO_IMPLEMENT (), 0);
+}
+
+::CORBA::StringSeq * CIAO_RepositoryManagerDaemon_i::getAllNames (
+
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException
+ ))
+{
+ // Add your implementation here
+
+ CORBA::ULong num_entries = this->names_.current_size ();
+ CORBA::StringSeq_var seq = new CORBA::StringSeq (num_entries);
+
+ CORBA::ULong index = 0;
+ for (PCMap_Iterator iter = this->names_.begin ();
+ iter != this->names_.end () && index < num_entries;
+ iter++)
+
+ seq[index] = const_cast<char*> (((*iter).int_id_).c_str ()); //this looks hideous, but as long as it works!
+
+
+ return seq._retn (); //release the underlying CORBA::StringSeq
+}
+
+::CORBA::StringSeq * CIAO_RepositoryManagerDaemon_i::getAllTypes (
+
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException
+ ))
+{
+ // Add your implementation here
+ ACE_THROW_RETURN (CORBA::NO_IMPLEMENT (), 0);
+}
+
+void CIAO_RepositoryManagerDaemon_i::deletePackage (
+ const char * installationName
+ )
+ ACE_THROW_SPEC ((
+ CORBA::SystemException,
+ ::Deployment::NoSuchName
+ ))
+{
+ // Add your implementation here
+
+ ACE_Hash_Map_Entry <ACE_CString, ACE_CString> *entry;
+
+ if (this->names_.find (ACE_CString (installationName), entry) != 0)
+ ACE_THROW (Deployment::NoSuchName ());
+ else
+ this->names_.unbind (installationName);
+
+ //do the same for the UUID!!!!
+ //TODO: NEED TO DO THIS LATER
+
+
+ //actually delete the package here!
+ //TODO: Check if files are ref-counted by the OS, so if I delete it here while
+ //some other process is still using it from a previous request, would that cause an error,
+ //or would it decrement the recount and delete the file when the other process is done.
+ //
+ //on that note is a file handle is not closed the file does not get deleted! , so see how
+ //temp files work!
+
+ ACE_CString path (this->install_root_.c_str ());
+ path += "/";
+ path += installationName;
+
+ ACE_CString package_path (path);
+ package_path += ".cpk"; //package extension
+
+ ACE_CString pc_path (path);
+ pc_path += PC_EXTENSION; //external PackageConfiguration extension
+
+ remove_extracted_package (package_path.c_str (), path.c_str ());
+
+ remove (package_path.c_str ());
+ remove (pc_path.c_str ());
+}
+
+//==========================================HELPER METHODS==================================================
+
+Deployment::PackageConfiguration*
+CIAO_RepositoryManagerDaemon_i::retrieve_PC_from_package (char* package)
+{
+ char temp[128];
+ // ACE_thread_t thread_id = ACE_Thread::self ();
+ char* PID = ACE_OS::itoa (ACE_OS::getpid (), temp, 10);
+
+ ACE_OS::mkdir(PID);
+ //if dir already exists a -1 is returned
+ //we ignore this, just need to make sure the directory exists
+
+ //change the working dir
+ ACE_OS::chdir (PID);
+
+ ACE_CString pcd_name;
+ //extract the necessary descriptors
+ if (extract_descriptor_files (package,
+ pcd_name) < 0)
+ {
+ ACE_OS::chdir (this->cwd_);
+ ACE_ERROR ((LM_ERROR,
+ "(%P|%t) RepositoryManager: error extracting necessary files\n"));
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ Deployment::PackageConfiguration_var pc;
+ //parse the PCD to make sure that there are no package errors
+ ACE_TRY
+ {
+ CIAO::Config_Handlers::STD_PC_Intf intf (pcd_name.c_str ());
+
+ pc = intf.get_PC ();
+ }
+ ACE_CATCHALL
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%P|%t) RepositoryManager: Error parsing the PCD\n"));
+
+ //change back the the old working dir
+ ACE_OS::chdir (this->cwd_);
+ ACE_THROW (Deployment::PackageError ());
+ }
+ ACE_ENDTRY;
+ //able to parse the PC. So lets install the package in the repo
+
+ //we no longer need the descriptors, so lets erase them!
+ remove_descriptor_files (package);
+
+ //change back the the old working dir
+ ACE_OS::chdir (this->cwd_);
+
+ //now lets erase the directory!
+ ACE_OS::rmdir (PID);
+ //the ACE_OS::rmdir does not work. Possibly because we need to delete
+ //the contents first. I will look into it more closely when I am back.
+
+ return pc._retn ();
+}
+
+
+//function to parse and return the PackageConfiguration from the already
+//extracted descriptor files
+Deployment::PackageConfiguration*
+CIAO_RepositoryManagerDaemon_i::retrieve_PC_from_descriptors (const char* pc_name,
+ const char* descriptor_dir)
+{
+ //change the working dir
+ ACE_OS::chdir (descriptor_dir);
+
+ Deployment::PackageConfiguration_var pc;
+ //parse the PCD to make sure that there are no package errors
+ ACE_TRY
+ {
+ CIAO::Config_Handlers::STD_PC_Intf intf (pc_name);
+
+ pc = intf.get_PC ();
+ }
+ ACE_CATCHALL
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%P|%t) [RM::retrieve_PC_from_descriptors] Error parsing the PCD\n"));
+
+ //change back the the old working dir
+ ACE_OS::chdir (this->cwd_);
+ ACE_THROW (Deployment::PackageError ());
+ }
+ ACE_ENDTRY;
+ //able to parse the PC. So lets install the package in the repo
+
+ //change back the the old working dir
+ ACE_OS::chdir (this->cwd_);
+
+ return pc._retn ();
+}
+
+
+//find out what the name of the PackageConfiguration file is
+void CIAO_RepositoryManagerDaemon_i::find_PC_name (char* package, ACE_CString& pcd_name)
+{
+ pcd_name = ""; //empty the contents of the ACE_CString
+
+ //create a doubly link list
+ ACE_New_Allocator allocator;
+ ACE_Double_Linked_List<ZIP_File_Info> list (&allocator);
+
+ //get the list of files in the package and figure out the names of all necessary files
+ if (!(ZIP_Wrapper::file_list_info (package, list)))
+ return;
+
+ size_t skip_len = ACE_OS::strlen ("descriptors") + 1;
+
+ while (!list.is_empty ())
+ {
+ ZIP_File_Info* inf = list.delete_head ();
+
+ if (ACE_OS::strstr (inf->name_.c_str (), "descriptors"))
+ if (ACE_OS::strstr (inf->name_.c_str (), ".pcd"))
+ pcd_name = inf->name_.c_str () + skip_len;
+
+ //deallocate the head of the filename list
+ delete inf;
+ }
+}
+
+
+//We are using Xercesc in the Config_Handlers and unfortunately its API only
+//takes a file in the local file system as an argument, thus need to
+//write out the contents of the deployent plan to a file
+//in the current directory. I use the thread id to guarrantee
+//lack of race conditions if multithreading is enabled
+
+int CIAO_RepositoryManagerDaemon_i::extract_descriptor_files (char* package, ACE_CString& pcd_name)
+{
+ //create a doubly link list
+ ACE_New_Allocator allocator;
+ ACE_Double_Linked_List<ZIP_File_Info> list (&allocator);
+
+ //get the list of files in the package and figure out the names of all necessary files
+ if (!(ZIP_Wrapper::file_list_info (package, list)))
+ return 0;
+
+ size_t skip_len = ACE_OS::strlen ("descriptors") + 1;
+
+ while (!list.is_empty ())
+ {
+ ZIP_File_Info* inf = list.delete_head ();
+ ACE_Message_Block* file = 0;
+ if (ACE_OS::strstr (inf->name_.c_str (), "descriptors"))
+ {
+ if (ACE_OS::strstr (inf->name_.c_str (), ".pcd"))
+ pcd_name = inf->name_.c_str () + skip_len;
+
+ //extract the descriptor from the package
+ file = new ACE_Message_Block (0,0);
+ if (!ZIP_Wrapper::get_file(const_cast<char*> (package),
+ const_cast<char*> (inf->name_.c_str ()),
+ *file))
+ {
+ ACE_ERROR ((LM_ERROR,
+ "[RM::extract_descriptor_files] Unable to retrieve file!\n"));
+ //release the message block chain
+ file->release ();
+ return 0;
+ }
+
+
+ //write the file to disk
+ if(!RM_Helper::write_to_disk (inf->name_.c_str () + skip_len, *file))
+ {
+ ACE_ERROR ((LM_ERROR,
+ "[RM::extract_descriptor_files] Unable to write out descriptor to disk!\n"));
+ //release the message block chain
+ file->release ();
+ return 0;
+ }
+
+ //release the message block chain
+ file->release ();
+ }
+
+ //deallocate the head of the filename list
+ delete inf;
+ }
+
+ return 1;
+}
+
+int CIAO_RepositoryManagerDaemon_i::remove_descriptor_files (char* package)
+{
+ int return_code = 1;
+
+ //create a doubly link list
+ ACE_New_Allocator allocator;
+ ACE_Double_Linked_List<ZIP_File_Info> list (&allocator);
+
+ //get the list of files in the package and figure out the names of all necessary files
+ if (!(ZIP_Wrapper::file_list_info (package, list)))
+ return 0;
+
+ size_t skip_len = ACE_OS::strlen ("descriptors") + 1;
+
+ while (!list.is_empty ())
+ {
+ ZIP_File_Info* inf = list.delete_head ();
+ if (ACE_OS::strstr (inf->name_.c_str (), "descriptors"))
+ {
+ //delete disk
+ if(remove (inf->name_.c_str () + skip_len))
+ {
+ ACE_ERROR ((LM_ERROR,
+ "[RM::remove_descriptor_files] Unable to write out descriptor to disk!\n"));
+ return_code = 0;
+ }
+ }
+ //deallocate the head of the filename list
+ delete inf;
+ }
+
+ return return_code;
+}
+
+//function to remove the files extracted from the package upon istallation
+//It reads the names of the files from the package. They correspond to the
+//names on disk. It deletes each file, then it deletes the directories that
+//contain them.
+//return 1 on success
+// 0 on error
+
+int CIAO_RepositoryManagerDaemon_i::remove_extracted_package
+(const char* package_path,
+ const char* extraction_location)
+{
+ //change the working dir
+ if (ACE_OS::chdir (extraction_location) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "[RM::remove_extracted_package] Unable to chdir to doomed directory!\n"),
+ 0);
+
+ int return_code = 1;
+
+ //create a doubly link list
+ ACE_New_Allocator allocator;
+ ACE_Double_Linked_List<ZIP_File_Info> list (&allocator);
+
+ //get the list of files in the package and figure out the names of all necessary files
+ if (!(ZIP_Wrapper::file_list_info (const_cast <char*> (package_path), list)))
+ {
+ //change back the the old working dir
+ ACE_OS::chdir (this->cwd_);
+ return 0;
+ }
+
+ while (!list.is_empty ())
+ {
+ ZIP_File_Info* inf = list.delete_head ();
+
+ //delete file from disk
+ if(remove (inf->name_.c_str ()))
+ {
+ ACE_ERROR ((LM_ERROR,
+ "[RM::remove_extracted files] Unable to delete %s!\n", inf->name_.c_str ()));
+ return_code = 0;
+ }
+
+ //deallocate the head of the filename list
+ delete inf;
+ }
+
+ //now remove the descriptors and implementations directories.
+ ACE_OS::rmdir ("descriptors");
+ ACE_OS::rmdir ("implementations");
+
+ //now go one directory up and delete the extraction directory
+ ACE_OS::chdir (this->install_root_.c_str ());
+ ACE_OS::rmdir (extraction_location);
+
+ //change back the the old working dir
+ ACE_OS::chdir (this->cwd_);
+
+ return return_code;
+}
+
+