diff options
Diffstat (limited to 'CIAO/DAnCE/RepositoryManager')
19 files changed, 3789 insertions, 0 deletions
diff --git a/CIAO/DAnCE/RepositoryManager/Options.cpp b/CIAO/DAnCE/RepositoryManager/Options.cpp new file mode 100644 index 00000000000..a9fd5a67d3d --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/Options.cpp @@ -0,0 +1,147 @@ +// $Id$ + +// Options.cpp,v Stoyan + +#include "ace/Get_Opt.h" +#include "ace/ARGV.h" +#include "Options.h" + + +bool +Options::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("ov:n:l:u:t:icfdsTNa")); + + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'o': + this->write_to_ior_ = true; + this->register_with_ns_ = false; + break; + case 'v': + this->write_to_ior_ = false; + this->register_with_ns_ = true; + this->repoman_name_ = get_opt.opt_arg (); + break; + case 'i': + this->install_ = true; + break; + case 'c': + this->create_ = true; + break; + case 'd': + this->delete_ = true; + break; + case 'f': + this->find_ = true; + break; + case 's': + this->shutdown_ = true; + break; + case 'n': + this->name_ = get_opt.opt_arg (); + break; + case 'l': + this->path_ = get_opt.opt_arg (); + break; + case 'u': + this->uuid_ = get_opt.opt_arg (); + break; + case 'N': + this->all_names_ = true; + break; + case 'T': + this->all_types_ = true; + break; + case 't': + this->names_by_type_ = true; + this->type_ = get_opt.opt_arg (); + break; + // Usage fallthrough. + default: + this->usage (); + return false; + } + + if ((this->name_ == "") + && (this->shutdown_ == false) + && (this->uuid_ == "") + && (this->all_names_ == false) + && (this->all_types_ == false) + && (this->names_by_type_ == false)) + { + this->usage (); + return false; + } + else if (this->name_ != "") + { + if (!(this->install_ || this->create_ || this->find_ || this->delete_)) + { + this->usage (); + return false; + } + else if (this->install_ && this->path_ == "") + { + this->usage (); + return false; + } + else if (this->create_ && this->path_ == "") + { + this->usage (); + return false; + } + } + else if (this->uuid_ != "") + { + if (!this->find_) + { + this->usage (); + return false; + } + } + + return true; +} + +/// @todo Exit is not nice, return -1 so that the caller can do something and +/// we don't exit abruptly +void Options::usage (void) +{ + ACE_DEBUG ((LM_INFO, "OPTIONS: \n\ + -o <using ior file> \n\ + -v <: name of naming service> \n\ + -s <shutdown> \n\ + -n <:name> \n\ + [-i <install> -l <:path>] \n\ + [-c <create> -l <:path>] \n\ + [-d <delete>] \n\ + [-f <find>] \n\ + -u <:uuid> \n\ + [-f <find>] \n\ + -a <names by type> \n\ + [-t <:type>] \n\ + -N <all names> \n\ + -T <all types> \n")); +} + +Options::Options (void) + : name_ (""), + uuid_ (""), + type_ (""), + path_ (""), + delete_ (false), + install_ (false), + create_ (false), + find_ (false), + all_names_ (false), + all_types_ (false), + names_by_type_ (false), + shutdown_ (false), + register_with_ns_ (false), + write_to_ior_ (true), + repoman_name_ ("") +{ +} diff --git a/CIAO/DAnCE/RepositoryManager/Options.h b/CIAO/DAnCE/RepositoryManager/Options.h new file mode 100644 index 00000000000..845e339cedd --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/Options.h @@ -0,0 +1,93 @@ +// $Id$ + +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Options.h + * + * $Id$ + * + * TheOptions is an Options class wrapped into an ACE_Singleton + * with Null_Mutex because the client is single-threaded. + * + * + * @author Stoyan Paunov + */ +//============================================================================= + + +#ifndef RM_OPTIONS_H +#define RM_OPTIONS_H + +#include "ace/Get_Opt.h" +#include "ace/SString.h" //for ACE_CString +#include "ace/Singleton.h" //for ACE_Singleton +#include "ace/Null_Mutex.h" //for ACE_Null_Mutex + +//forward declaration +class Options; + +typedef ACE_Singleton <Options, ACE_Null_Mutex> TheOptions; + +class Options +{ +public: + + ///constructor + Options (void); + + /// parses commandline arguments + bool parse_args (int argc, ACE_TCHAR *argv[]); + + /// Name of package + ACE_CString name_; + + /// Name of package + ACE_CString uuid_; + + /// Type of package + ACE_CString type_; + + /// specifies the local path for install + ACE_CString path_; + + /// delete the name_ + bool delete_; + + /// installs the name_ + bool install_; + + /// creates the name_ + bool create_; + + /// finds the name_ + bool find_; + + /// get all Names + bool all_names_; + + /// get all types + bool all_types_; + + /// find all names by type + bool names_by_type_; + + /// shutdown the RepositoryManagerDemon + bool shutdown_; + + // use naming service + bool register_with_ns_; + + // use ior file + bool write_to_ior_; + + // Name of RepoMan + ACE_CString repoman_name_; + +protected: + //usage function + void usage (void); +}; + +#endif /* RM_OPTIONS_H */ diff --git a/CIAO/DAnCE/RepositoryManager/PC_Updater.cpp b/CIAO/DAnCE/RepositoryManager/PC_Updater.cpp new file mode 100644 index 00000000000..1acd3d8c4b9 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/PC_Updater.cpp @@ -0,0 +1,256 @@ +// $Id$ + +#include "ace/Log_Msg.h" +#include "DAnCE/Deployment/Deployment_DataC.h" +#include "PC_Updater.h" +#include "PC_Updater_T.h" +#include "ace/Containers_T.h" //for ACE_Double_Linked_List + +namespace +{ + const size_t TEMP_LEN = 1024; +} + +using namespace PC_Updater_T; + + + //PATH of glory/gory to update the locations of the IADs + // + //PackageConfiguration something; + //ComponentPackageDescriptions basePackage; + //PackagedComponentImplementations implementation; + //ComponentImplementationDescription referencedImplementation; + // + //MONOLITHIC Component: + //MonolithicImplementationDescriptions monolithicImpl; + //NamedImplementationArtifacts primaryArtifact; + //ImplementationArtifactDescription referencedArtifact; + //::CORBA::StringSeq location; + // + //ASSEMBLY-BASED Component + //ComponentAssemblyDescriptions assemblyImpl; + //SubcomponentInstantiationDescriptions instance; + //ComponentPackageDescriptions package; + //... + + + /* + * PC_Updater Constructors + */ + +PC_Updater::PC_Updater (const char* server_path, const char* package) +: server_path_ (server_path), + file_list_ (), + package_ (package), + success_ (true) +{ +} + + +PC_Updater::PC_Updater (ACE_CString& server_path, ACE_CString& package) +: server_path_ (server_path), + file_list_ (), + package_ (package), + success_ (true) +{ +} + + /* + * PC_Updater - Destructor + */ + +PC_Updater::~PC_Updater () +{ + this->clear_list (); +} + + +void PC_Updater::clear_list () +{ + while (!this->file_list_.is_empty ()) + { + ZIP_File_Info* inf = this->file_list_.delete_head (); + + //deallocate the head of the filename list + delete inf; + } +} + + + /* + * PC_Updater - Object update methods + */ + + + // PackageConfiguration + + bool PC_Updater::update (::Deployment::PackageConfiguration &pc) + { + //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*> (this->package_.c_str ()), this->file_list_)) + return false; + + update_sequence (pc.basePackage, this); + + return this->success_; + } + + + // ComponentInterfaceDescription + + void PC_Updater::update (::Deployment::ComponentInterfaceDescription &) + { + } + + // Requirement + + void PC_Updater::update (::Deployment::Requirement &) + { + } + + + // ComponentExternalPortEndpoint + + void PC_Updater::update (::Deployment::ComponentExternalPortEndpoint &) + { + } + + + + // ImplementationDependency + + void PC_Updater::update (Deployment::ImplementationDependency &) + { + } + + // ComponentPackageReference + + void PC_Updater::update (::Deployment::ComponentPackageReference &) + { + } + + // SubcomponentInstantiationDescription + + void PC_Updater::update (::Deployment::SubcomponentInstantiationDescription &sid) + { + update_sequence (sid.basePackage, this); + } + + // SubcomponentPortEndpoint + + void PC_Updater::update (::Deployment::SubcomponentPortEndpoint& ) + { + } + + // AssemblyConnectionDescription + + void PC_Updater::update (::Deployment::AssemblyConnectionDescription &) + { + } + + + // AssemblyPropertyMapping + + void + PC_Updater::update (::Deployment::AssemblyPropertyMapping &) + { + } + + // ComponentAssemblyDescription + + void PC_Updater::update (::Deployment::ComponentAssemblyDescription& cad) + { + update_sequence (cad.instance, this); + } + + // ImplementationArtifactDescription + + void PC_Updater::update (::Deployment::ImplementationArtifactDescription &iad) + { + const char* location = CORBA::string_dup (iad.location[0]); + + //create an iterator + ACE_Double_Linked_List_Iterator<ZIP_File_Info> iter (this->file_list_); + + //find the correct path and return + while (!iter.done ()) + { + const char* full_path = iter.next ()->name_.c_str (); + //weird. Need to call next to get current ?!?! + + //is it an implementation artifact? + const char* name = ACE_OS::strstr (full_path, "implementations/"); + if (name) + { + //now check if the name matches + name = ACE_OS::strstr (full_path, iad.location[0]); + + if (name) + { + ACE_CString loc (this->server_path_); + loc += "/implementations/"; + loc += location; + + iad.location[0] = CORBA::string_dup (loc.c_str ()); + + //cout << "Location after update: " << iad.location[0] << endl << endl; + return; + } + } + iter++; + } + + ACE_ERROR ((LM_ERROR, + "[PC_Updater::update] Unable to update: %s!\n", + location)); + + this->success_ = false; + } + + // NamedImplementationArtifact + + void PC_Updater::update (::Deployment::NamedImplementationArtifact &nia) + { + update (nia.referencedArtifact); + } + + // ImplementationRequirement + void PC_Updater::update (::Deployment::ImplementationRequirement &) + { + } + + // MonolithicImplementationDescription + void PC_Updater::update (::Deployment::MonolithicImplementationDescription &mid) + { + update_sequence (mid.primaryArtifact, this); + } + + // Capability + void PC_Updater::update (::Deployment::Capability &) + { + } + + // ComponentImplementationDescription + void PC_Updater::update (::Deployment::ComponentImplementationDescription &cid) + { + update_sequence (cid.assemblyImpl, this); + update_sequence (cid.monolithicImpl, this); + } + + // PackagedComponentImplementation + void PC_Updater::update (::Deployment::PackagedComponentImplementation &pci) + { + PC_Updater::update (pci.referencedImplementation); + } + + // ComponentPackageDescription + void PC_Updater::update (::Deployment::ComponentPackageDescription &comppkgdesc) + { + update_sequence (comppkgdesc.implementation, this); + } + + + // Property + void PC_Updater::update (Deployment::Property& ) + { + } diff --git a/CIAO/DAnCE/RepositoryManager/PC_Updater.h b/CIAO/DAnCE/RepositoryManager/PC_Updater.h new file mode 100644 index 00000000000..5b22e249331 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/PC_Updater.h @@ -0,0 +1,113 @@ + +/* -*- C++ -*- */ + +//======================================================================== +/** + * file PC_Updater.h + * + * $Id$ + * + * This class is used to update the location field of the implementation + * artifacts in the PackageConfiguration, so that they point to the + * physical libraries on the collocated HTTP server + * + * author Stoyan Paunov <spaunov@isis.vanderbilt.edu> + */ +//======================================================================== + +#ifndef PC_UPDATER_H +#define PC_UPDATER_H +#include /**/ "ace/pre.h" + +#include "DAnCE/Deployment/DeploymentC.h" +#include "ace/SString.h" //for the ACE_CString + +#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 + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +/** + * @class PC_Updater + * + * This class defines a set of overloaded methods used to update + * the contents of a PackageConfiguration. More specifically the class + * goes through the PackageConfiguration and updates the locations of the + * artifacts, wrt to their location on the HTTP server. + */ +class PC_Updater +{ +public: + + /// Constructors + + PC_Updater (const char* server_path, const char* package); + PC_Updater (ACE_CString& server_path, ACE_CString& package); + + ~PC_Updater (); + + /// A whole slew of overloaded routines for different IDL + /// data types part of the PackageConfiguration. + + bool update (::Deployment::PackageConfiguration &pc); + + void update (::Deployment::Property &property); + + void update (::Deployment::AssemblyConnectionDescription &acd); + + void update (::Deployment::AssemblyPropertyMapping &apm); + + void update (::Deployment::ComponentPackageDescription &comppkgdesc); + + void update (::Deployment::MonolithicImplementationDescription &mid); + + void update (::Deployment::PackagedComponentImplementation &pci); + + void update (::Deployment::SubcomponentPortEndpoint &spe); + + void update (::Deployment::Requirement &requirement); + + void update (::Deployment::ComponentExternalPortEndpoint &cepe); + + void update (::Deployment::ComponentPackageReference &cpr); + + void update (::Deployment::ComponentImplementationDescription &cid); + + void update (::Deployment::SubcomponentInstantiationDescription &sid); + + void update (::Deployment::NamedImplementationArtifact &named_implementation); + + void update (::Deployment::ComponentInterfaceDescription &cid); + + void update (::Deployment::Capability &capability); + + void update (::Deployment::ImplementationArtifactDescription &iad); + + void update (::Deployment::ImplementationRequirement &ir); + + void update (::Deployment::ImplementationDependency &id); + + void update (::Deployment::ComponentAssemblyDescription& cad); + +protected: + + void clear_list (); + +private: + + ACE_CString server_path_; + + /// create a doubly link list + //ACE_New_Allocator allocator_; + ACE_Double_Linked_List<ZIP_File_Info> file_list_; + + ACE_CString package_; + bool success_; +}; + +#include /**/ "ace/post.h" + +#endif /* PC_UPDATER_H */ diff --git a/CIAO/DAnCE/RepositoryManager/PC_Updater_T.cpp b/CIAO/DAnCE/RepositoryManager/PC_Updater_T.cpp new file mode 100644 index 00000000000..a5f5ec5fb2e --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/PC_Updater_T.cpp @@ -0,0 +1,20 @@ +// $Id$ +#ifndef PC_UPDATER_T_C +#define PC_UPDATER_T_C +#include "PC_Updater.h" +#include "PC_Updater_T.h" + +namespace PC_Updater_T +{ + /// Dumps a sequence + template <typename SEQUENCE> + void update_sequence (SEQUENCE &seq, PC_Updater* updater) + { + CORBA::ULong const size = seq.length (); + + for (CORBA::ULong i = 0; i < size; ++i) + updater->update (seq[i]); + } +} + +#endif /* PC_Updater_C */ diff --git a/CIAO/DAnCE/RepositoryManager/PC_Updater_T.h b/CIAO/DAnCE/RepositoryManager/PC_Updater_T.h new file mode 100644 index 00000000000..0696c685e2b --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/PC_Updater_T.h @@ -0,0 +1,40 @@ + +/* -*- C++ -*- */ + +//================================================================== +/** + * file PC_Updater_T.h + * + * $Id$ + * + * author Stoyan Paunov <spaunov@isis.vanderbilt.edu> + */ +//===================================================================== + +#ifndef CIAO_CONFIG_HANDLERS_PC_UPDATER_T_H +#define CIAO_CONFIG_HANDLERS_PC_UPDATER_T_H +#include /**/ "ace/pre.h" + +#include "ace/config-lite.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace PC_Updater_T +{ + template <typename SEQUENCE> + static void update_sequence (SEQUENCE &seq); +} + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "PC_Updater_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("PC_Updater_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + + +#include /**/ "ace/post.h" +#endif /*CIAO_CONFIG_HANDLERS_PC_Updater_T_H*/ diff --git a/CIAO/DAnCE/RepositoryManager/README b/CIAO/DAnCE/RepositoryManager/README new file mode 100644 index 00000000000..322b00098ac --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/README @@ -0,0 +1,46 @@ +This is the README file for the Repository Manager (RM). + +Building RM: +In order to be able to compile the RM you need to have ZLIB lib because the RM +uses it to read the contents of CCM packages. In order to compile the RM +successfully you will need to do the following: +1.Download the binary version of ZLIB or build it yourself +3.Create an "include" and a "lib" subdirectory. Then copy the libraries files into + the "lib" subdirectory and copy zlib.h into the "include" subdirectory. +4.Set $ZLIB_ROOT to point to the directories where you placed the libraries and + the include files. +5.Turn on zzip and zlib in default.features for MPC. +6.MPC will handle the rest. + +If you want to get the component package through http server: +1.Be sure to set JAWS_DOCUMENT_ROOT to the installation path of the RepoMan, i.e., $CIAO_ROOT/DAnCE/RepositoryManager. +2.Start JAWS: $ACE_ROOT/apps/JAWS/server/main + +Start RM: +1.Using ior file: + RepositoryManagerDaemon -o +2.Using Naming Service: + RepositoryManagerDaemon -v [NameofRM] + +Using RMadmin: +1.Install component package: (use BasicSP for example) + Be sure you have BasicSP.cpk in the $CIAO_ROOT/DAnCE/RepositoryManager/packages + > RMadmin -o -n BasicSP -i -l packages/BasicSP.cpk + or + > RMadmin -o -n BasicSP -i -l http://127.0.0.1:5432/packages/BasicSP.cpk (If the JAWS is started) + This will create the BasicSP directory, BasicSP.cpk file and BasicSP.epc file in the + $CIAO_ROOT/DAnCE/RepositoryManager/RepositoryManager/ +2.Delete component package: (use BasicSP for example) + > RMadmin -o -n BasicSP -d +3.Find component package by its name: (use BasicSP for example) + > RMadmin -o -n BasicSP -f +4.Stop RM: + > RMadmin -o -s + This will create the RM_record file in the $CIAO_ROOT/DAnCE/RepositoryManager/RepositoryManager/ which record the + names and UUIDs of the installed component packages. + + + + + + diff --git a/CIAO/DAnCE/RepositoryManager/RM_Helper.cpp b/CIAO/DAnCE/RepositoryManager/RM_Helper.cpp new file mode 100644 index 00000000000..cd4b92669d0 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RM_Helper.cpp @@ -0,0 +1,265 @@ +// $Id$ + +#include "RM_Helper.h" +#include "ace/Auto_Ptr.h" //for Auto_Ptr +#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 mkdir +#include "ace/OS_NS_string.h" + + +void +RM_Helper::pc_to_cdr (const Deployment::PackageConfiguration& pc, TAO_OutputCDR& cdr) +{ + cdr << pc; +} + + +void +RM_Helper::cdr_to_pc (Deployment::PackageConfiguration& pc, TAO_InputCDR& cdr) +{ + cdr >> pc; +} + + +bool +RM_Helper::externalize (const Deployment::PackageConfiguration& pc, const char* path) +{ + size_t bufsiz = 0; + TAO_OutputCDR out (bufsiz); + + RM_Helper::pc_to_cdr (pc, out); + + const ACE_Message_Block* mb = out.begin (); + + return write_pc_to_disk (path, *(const_cast<ACE_Message_Block*> (mb))); +} + + +bool +RM_Helper::reincarnate (Deployment::PackageConfiguration& pc, const char* path) +{ + size_t length = 0; + ACE_Auto_Ptr<ACE_Message_Block> mb (read_pc_from_disk (path, length)); + + if (!mb.get ()) + return false; + + TAO_InputCDR in (mb.get ()); + + RM_Helper::cdr_to_pc (pc, in); + + return true; +} + + +/// This function attempts to copy the file from a specified location +/// to another specified location on the hard disk. +bool +RM_Helper::copy_from_disk_to_disk (const char* from_path, const char* to_path) +{ + if (ACE_OS::strcmp (from_path, to_path) == 0) + return true; + + // Open the files + ACE_HANDLE from_handle = ACE_OS::open (from_path, O_RDONLY); + if (from_handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::copy_from_disk_to_disk] file open error")), + 0); + + ACE_stat file_info; + ACE_OS::fstat (from_handle, &file_info); + ACE_UINT64 file_length = file_info.st_size; + + ACE_HANDLE to_handle = ACE_OS::open (to_path, O_CREAT | O_TRUNC | O_WRONLY); + if (to_handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::copy_from_disk_to_disk] file creation error")), + 0); + + + // Read the contents of the file into the buffer and write the data to another file + ACE_Message_Block *mb = 0; + size_t length; + size_t number = 0; + bool last = false; + + while (true) + { + if ((file_length - BUFSIZ*number) > BUFSIZ) + length = BUFSIZ; + else + { + length = static_cast<size_t> (file_length - BUFSIZ*number); + last = true; + } + + mb = new ACE_Message_Block (length); + + if (ACE_OS::read_n (from_handle, mb->wr_ptr (), length) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::copy_from_disk_to_disk] file read error")), + 0); + + ++number; + + mb->length (length); + + for (ACE_Message_Block *curr = mb; curr != 0; curr = curr->cont ()) + if (ACE_OS::write_n (to_handle, curr->rd_ptr (), curr->length ()) == -1) + { + mb->release (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::copy_from_disk_to_disk] file write error")), + 0); + } + + mb->release (); + + if (last) + break; + } + + // Close the files + ACE_OS::close (from_handle); + ACE_OS::close (to_handle); + + return true; +} + + +/// This function attempts to write a sequence of bytes from an +/// ACE_Message_Block to a specified location. A 0 is returned +/// in the case of an error and a 1 upon success +bool RM_Helper::write_to_disk ( + const char* full_path, + ACE_Message_Block& mb, + bool replace + ) +{ + ACE_stat stat; + + if (ACE_OS::stat(full_path, &stat) != -1 && !replace) + return false; + + // Open a file handle to the local filesystem + ACE_HANDLE handle = ACE_OS::open (full_path, O_CREAT | O_TRUNC | O_WRONLY); + if (handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::write_to_disk] file creation error")), + false); + + // Write the data to the file + for (ACE_Message_Block * curr = &mb; curr != 0; curr = curr->cont ()) + if (ACE_OS::write_n (handle, curr->rd_ptr(), curr->length()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write error")), + false); + + // Close the file handle + ACE_OS::close (handle); + + return true; +} + + +/// This function attempts to write a sequence of bytes from an +/// ACE_Message_Block to a specified location. A 0 is returned +/// in the case of an error and a 1 upon success +/// +/// @note This function write the contents in a way that preserves the +/// structure of the ACE_Message_Block. It is relevant for +/// PackageConfigurations ONLY +bool RM_Helper::write_pc_to_disk ( + const char* full_path, + ACE_Message_Block& mb, + bool replace + ) +{ + ACE_stat stat; + + if (ACE_OS::stat(full_path, &stat) != -1 && !replace) + return false; + + // Open a file handle to the local filesystem + ACE_HANDLE const handle = ACE_OS::open (full_path, O_CREAT | O_TRUNC | O_WRONLY); + if (handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::write_to_disk] file creation error")), + false); + + // write the data to the file + for (ACE_Message_Block * curr = &mb; curr != 0; curr = curr->cont ()) + if (ACE_OS::write_n (handle, curr->rd_ptr(), curr->length()) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write error")), + 0); + + // Close the file handle + ACE_OS::close (handle); + + return true; +} + + +/// Function to read the contents of a file from disk into an ACE_Message_Block +/// returns a pointer to an ACE_Message_Block and updates the lenght on success +/// 0 on failure +ACE_Message_Block* +RM_Helper::read_pc_from_disk ( + const char* full_path, + size_t &length + ) +{ + length = 0; + + // Open the file + ACE_HANDLE const handle = ACE_OS::open (full_path, O_RDONLY); + if (handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::read_mb_from_disk] file open error")), + 0); + + ACE_stat file_info; + ACE_OS::fstat (handle, &file_info); + + // Get and check the length of the file + length = static_cast<size_t> (file_info.st_size); + + ACE_INT64 check = length; + if (check != file_info.st_size) + { + length = 0; + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::read_mb_from_disk] file length error")), + 0); + } + + // Read the contents of the file into the buffer + ACE_Message_Block* mb = 0; + ACE_NEW_RETURN (mb, ACE_Message_Block (length + 1), 0); + + if (ACE_OS::read_n (handle, mb->wr_ptr (), length) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[RM::read_mb_from_disk] file read error")), + 0); + + mb->length (length); + + // Close the file handle + ACE_OS::close (handle); + + return mb; +} diff --git a/CIAO/DAnCE/RepositoryManager/RM_Helper.h b/CIAO/DAnCE/RepositoryManager/RM_Helper.h new file mode 100644 index 00000000000..47e46d35a6f --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RM_Helper.h @@ -0,0 +1,81 @@ + +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file RM_Helper.h + * + * $Id$ + * + * This class aggregates a number of helper functions used by the + * CIAO RepositoryManager + * + * + * @author Stoyan Paunov + */ +//============================================================================= + +#ifndef RM_HELPER_H_ +#define RM_HELPER_H_ + + +#include "DAnCE/Deployment/Deployment_Packaging_DataC.h" +#include "tao/CDR.h" +#include "ace/Message_Block.h" + + +class RM_Helper +{ +public: + + static void pc_to_cdr (const Deployment::PackageConfiguration& pc, TAO_OutputCDR& cdr); + + static void cdr_to_pc (Deployment::PackageConfiguration& pc, TAO_InputCDR& cdr); + + static bool externalize (const Deployment::PackageConfiguration& pc, const char* path); + + static bool reincarnate (Deployment::PackageConfiguration& pc, const char* path); + + /** + * Function that copies the file from a specified location to another + * specified location on the hard disk. + * @retval true on success + * @retval false on error + */ + static bool copy_from_disk_to_disk (const char* from_path, const char* to_path); + + /** + * Function that writes out a file to a specified location on the hard disk + * @retval true on success + * @retval false on already exists and replace == false + * @retval false on error + */ + static bool write_to_disk (const char* full_path, + ACE_Message_Block& mb, + bool replace = true + ); + + /** + * Function that writes out a file to a specified location on the hard disk + * @retval true on success + * @retval false on already exists and replace == false + * @retval 0 on error + * @note This function is relevant for PackageConfigurations ONLY + */ + static bool write_pc_to_disk (const char* full_path, + ACE_Message_Block& mb, + bool replace = true); + + /** + * Function to read the contents of a file from disk into an + * ACE_Message_Block returns a pointer to an ACE_Message_Block and updates + * the lenght on success + * @retval 0 on failure + */ + + static ACE_Message_Block* read_pc_from_disk (const char* full_path, + size_t &length); + +}; + +#endif diff --git a/CIAO/DAnCE/RepositoryManager/RMadmin.cpp b/CIAO/DAnCE/RepositoryManager/RMadmin.cpp new file mode 100644 index 00000000000..f61a9f2a71e --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RMadmin.cpp @@ -0,0 +1,249 @@ +/* -*- C++ -*- */ + +/*** + * file RMClient.cpp + * + * $Id$ + * + * A sample client to the RepositoryManager showcasing how to use it + * + * author Stoyan Paunov <spaunov@isis.vanderbilt.edu> + * Shanshan Jiang <shanshan.jiang@vanderbilt.edu> + **/ + +#include "RepositoryManagerDaemonC.h" +#include "Options.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/streams.h" + +#include "Config_Handlers/DnC_Dump.h" + +#include "RM_Helper.h" //to be able to externalize/internalize a PackageConfiguration +#include "tao/CDR.h" //for TAO CDR classes +#include "ace/Message_Block.h" //for ACE_Message_Block + +#include "Package_Handlers/PCD_Handler.h" + +#include "orbsvcs/CosNamingC.h" + + +//IOR file of the RM +static const char *ior = "file://RepositoryManagerDaemon.ior"; + +// Name service of the RM +static const char *RMname_service; + +/// main function that provides a sample interface for RM clients +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + try + { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init (argc, argv, + ""); + + + Options* options = TheOptions::instance (); + if (!options->parse_args (argc, argv)) + return -1; + + CORBA::Object_var obj; + + if (options->write_to_ior_) + { + obj = orb->string_to_object (ior); + } + + else if (options->register_with_ns_) + { + if (options->repoman_name_ != "") + RMname_service = const_cast<char*> (options->repoman_name_.c_str ()); + + // Naming Service related operations + CORBA::Object_var naming_context_object = + orb->resolve_initial_references ("NameService"); + + CosNaming::NamingContext_var naming_context = + CosNaming::NamingContext::_narrow (naming_context_object.in ()); + + // Initialize the Naming Sequence + CosNaming::Name name (1); + name.length (1); + + // String dup required for MSVC6 + name[0].id = CORBA::string_dup (RMname_service); + + // Resolve object from name + obj = naming_context->resolve (name); + } + + + CIAO::RepositoryManagerDaemon_var rm = + CIAO::RepositoryManagerDaemon::_narrow (obj.in ()); + + if (CORBA::is_nil (rm.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + "Unable to acquire RepositoryManagerDaemon's objref\n"), + -1); + } + + if (options->shutdown_) + { + rm->shutdown (); + } + else if (options->all_names_) + { + try + { + CORBA::StringSeq_var seq = rm->getAllNames (); + cout << "Known Names:\n"; + for (size_t i = 0; + i < seq->length (); + ++i) + cout << seq[i] << endl; + } + catch (CORBA::Exception & ex) + { + cout << "\nException caught!" << ex << "\n"; + return 0; + } + } + else if (options->all_types_) + { + try + { + CORBA::StringSeq_var seq = rm->getAllTypes (); + cout << "Known Component Interface Types:\n"; + for (size_t i = 0; + i < seq->length (); + ++i) + cout << seq[i] << endl; + } + catch (CORBA::Exception & ex) + { + cout << "\nException caught!" << ex << "\n"; + return 0; + } + } + else if (options->type_ != "" && options->names_by_type_) + { + try + { + CORBA::StringSeq_var seq = rm->findNamesByType (options->type_.c_str ()); + cout << "Known Component Interface Types:\n"; + for (size_t i = 0; + i < seq->length (); + ++i) + cout << seq[i] << endl; + } + catch (CORBA::Exception & ex) + { + cout << "\nException caught!" << ex << "\n"; + return 0; + } + } + else if (options->install_) + { + try + { + rm->installPackage (options->name_.c_str (), options->path_.c_str (), false); + } + catch (CORBA::Exception & ex) + { + cout << "\nException caught!" << ex << "\n"; + return 0; + } + + cout << "\nReassuring that the package in the repository ..." << endl; + try + { + Deployment::PackageConfiguration_var pc = rm->findPackageByName (options->name_.c_str ()); + cout << "The package was found!" << endl; + cout << "Label: " << pc->label << endl; + cout << "UUID: " << pc->UUID << endl; + } + catch (CORBA::Exception &) + { + cout << "\nError! Package not found!" << endl; + } + } + else if (options->create_) + { + try + { + // Change the working dir. + char cwd [1024]; + ACE_OS::getcwd (cwd, 1024); + ACE_CString descriptor_dir (cwd); + descriptor_dir += "/packageDescriptors/RACE/descriptors/"; + ACE_OS::chdir (descriptor_dir.c_str ()); + + Deployment::PackageConfiguration *pc = new Deployment::PackageConfiguration (); + + // Parse the PCD to make sure that there are no package errors. + try + { + CIAO::Config_Handlers::Packaging::PCD_Handler::package_config ("default.pcd", *pc); + } + catch (...) + { + ACE_ERROR (( + LM_ERROR, + "(%P|%t) [RM::retrieve_PC_from_descriptors] Error parsing the PCD\n")); + + throw Deployment::PackageError (); + } + + ACE_OS::chdir (cwd); + + rm->createPackage (options->name_.c_str (), *pc, options->path_.c_str (), false); + } + catch (CORBA::Exception & ex) + { + cout << "\nException caught!" << ex << "\n"; + return 0; + } + } + else if (options->delete_) + { + try + { + rm->deletePackage (options->name_.c_str ()); + cout << options->name_.c_str () << " deleted" << endl; + } + catch (CORBA::Exception & ex) + { + cout << "\nException: " << ex << endl; + } + + } + else if (options->find_) + { + if (options->name_ != "") + { + Deployment::PackageConfiguration_var pc = rm->findPackageByName (options->name_.c_str ()); + cout << "The package was found!" << endl; + //Deployment::DnC_Dump::dump (pc); + } + else + { + Deployment::PackageConfiguration_var pc = rm->findPackageByUUID (options->uuid_.c_str ()); + cout << "The package was found!" << endl; + //Deployment::DnC_Dump::dump (pc); + } + } + + orb->shutdown (1); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ("Unknown exception \n"); + return -1; + } + + return 0; +} diff --git a/CIAO/DAnCE/RepositoryManager/RepositoryManager.cpp b/CIAO/DAnCE/RepositoryManager/RepositoryManager.cpp new file mode 100644 index 00000000000..5cefc3467c9 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RepositoryManager.cpp @@ -0,0 +1,279 @@ + +/* -*- C++ -*- */ + +//====================================================================== +/** + * @file RepositoryManager.cpp + * + * $Id$ + * + * Description: + * Main driver program for the CIAO RepositoryManager + * Please run as follows: + * RepositoryManagerDaemon [int:nthreads] + * + * @author Stoyan Paunov + */ +//====================================================================== + +#include "RepositoryManager_Impl.h" +#include "ace/OS_NS_stdio.h" +#include "ace/streams.h" +#include "ace/Auto_Ptr.h" +#include "ace/Task.h" +#include "ace/Get_Opt.h" +#include "ace/SString.h" + +#include "orbsvcs/CosNamingC.h" + +namespace CIAO +{ + namespace RepositoryManager + { + /// Name of the file holding the IOR of the RM + const char * RMior = "RepositoryManagerDaemon.ior"; + + // Name of RepoMan + const char * repoman_name_ = "RepositoryManager"; + + //Name service of the RM + const char * RMname_service = "RepositoryManager"; + + /// Default number of worker threads to run in the multi-threaded RM + static unsigned int nthreads = 3; + static ACE_CString HTTPserver = "127.0.0.1:5432"; + + static bool register_with_ns_ = false; + static bool write_to_ior_ = true; + } +} + +// Forward declaration +bool parse_args (int argc, char *argv[]); + +/** + * @class Worker + * + * Class that implements the service routine of the worker threads + * of the repository manager + */ +class Worker : public ACE_Task_Base +{ +public: + /// ctor + Worker (CORBA::ORB_ptr orb); + + /// The thread entry point. + virtual int svc (void); + +private: + /// The orb + CORBA::ORB_var orb_; +}; + +bool +write_ior_file (CORBA::ORB_ptr orb, + CIAO::RepositoryManagerDaemon_ptr obj) +{ + CORBA::String_var ior = + orb->object_to_string (obj); + + FILE* RMior_file = + ACE_OS::fopen (CIAO::RepositoryManager::RMior, "w"); + + if (RMior_file) + { + ACE_OS::fprintf (RMior_file, + "%s", + ior.in ()); + ACE_OS::fclose (RMior_file); + } + else + { + return false; + } + + return true; +} + +bool +register_with_ns (CORBA::ORB_ptr orb, + CIAO::RepositoryManagerDaemon_ptr obj) +{ + if (CIAO::RepositoryManager::repoman_name_ != "") + CIAO::RepositoryManager::RMname_service = + CIAO::RepositoryManager::repoman_name_; + + // Naming Service related operations + CORBA::Object_var naming_context_object = + orb->resolve_initial_references ("NameService"); + + CosNaming::NamingContext_var naming_context = + CosNaming::NamingContext::_narrow (naming_context_object.in ()); + + // Initialize the Naming Sequence + CosNaming::Name name (1); + name.length (1); + + // String dup required for MSVC6 + name[0].id = CORBA::string_dup (CIAO::RepositoryManager::RMname_service); + + // Register the servant with the Naming Service + naming_context->rebind (name, obj); + + return true; +} + +///Main function + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + try + { + //init the ORB + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + if (!parse_args (argc, argv)) + return -1; + + // Get the root POA object + CORBA::Object_var obj = orb->resolve_initial_references ("RootPOA"); + + // Downcast to POA type + PortableServer::POA_var root_poa = PortableServer::POA::_narrow (obj.in ()); + + //activate the POA manager + PortableServer::POAManager_var mgr = root_poa->the_POAManager (); + mgr->activate (); + + // Create a servant + CIAO_RepositoryManagerDaemon_i* repo = 0; + ACE_NEW_RETURN (repo, + CIAO_RepositoryManagerDaemon_i ( + orb.in (), + CIAO::RepositoryManager::HTTPserver.c_str (), + CIAO::RepositoryManager::repoman_name_), + 1); + + //transfer ownership to the POA + PortableServer::ServantBase_var owner_transfer(repo); + + //register and implicitly activate servant + CIAO::RepositoryManagerDaemon_var RepositoryManagerDaemon = repo->_this (); + + bool retval = false; + + if (CIAO::RepositoryManager::write_to_ior_) + { + retval = + write_ior_file (orb.in (), + RepositoryManagerDaemon.in ()); + } + else if (CIAO::RepositoryManager::register_with_ns_) + { + retval = + register_with_ns (orb.in (), + RepositoryManagerDaemon.in ()); + } + + if (!retval) + return -1; + + + Worker worker (orb.in ()); + if (worker.activate (THR_NEW_LWP | THR_JOINABLE, + CIAO::RepositoryManager::nthreads) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Cannot activate worker threads\n"), + 1); + + worker.thr_mgr ()->wait (); + + ACE_DEBUG ((LM_DEBUG, "event loop finished\n")); + + // done + return 0; + + // todo shutdown orb + } + catch (CORBA::Exception &ex) { + cerr << "CORBA Exception: " << ex << endl; + + return 1; + } + + + return 0; +} + + +// **************************************************************** + +///Code to parse the arguments + + bool + parse_args (int argc, char *argv[]) + { + ACE_Get_Opt get_opts (argc, argv, "ov:s:n:"); + int c; + while ((c = get_opts ()) != -1) + switch (c) + { + case 'o': + CIAO::RepositoryManager::write_to_ior_ = true; + CIAO::RepositoryManager::register_with_ns_ = false; + break; + case 'v': + CIAO::RepositoryManager::write_to_ior_ = false; + CIAO::RepositoryManager::register_with_ns_ = true; + CIAO::RepositoryManager::repoman_name_ = get_opts.opt_arg (); + break; + case 's': + CIAO::RepositoryManager::HTTPserver = get_opts.opt_arg (); + break; + case 'n': + CIAO::RepositoryManager::nthreads = ACE_OS::atoi (get_opts.opt_arg ()); + break; + case '?': // display help for use of the server. + ACE_DEBUG ((LM_INFO, + "usage: %s\n" + "-o <using ior file>\n" + "-v <name of naming service>\n" + "-s <IP:PORT for HTTP server>\n" + "-n <number of threads>\n", + argv [0])); + return false; + break; + default: + ; + } + + return true; + } + + + +// **************************************************************** + +///Constuctor for the worker class +Worker::Worker (CORBA::ORB_ptr orb) + : orb_ (CORBA::ORB::_duplicate (orb)) +{ +} + +///implementation of the service routine inherited from ACE::Task_Base + +int Worker::svc (void) +{ + try + { + this->orb_->run (); + } + catch (const CORBA::Exception&) + { + } + return 0; +} + + diff --git a/CIAO/DAnCE/RepositoryManager/RepositoryManager.mpc b/CIAO/DAnCE/RepositoryManager/RepositoryManager.mpc new file mode 100644 index 00000000000..d14d97843cd --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RepositoryManager.mpc @@ -0,0 +1,53 @@ +// -*- MPC -*- +// $Id$ + +//RepositoryManager project: implementation of a repository manager +//compleint with the D&C spec + +project (RepositoryManager) : ciao_server_dnc, ciao_config_handlers, zlib, ciaoexe { + + includes += $(CIAO_ROOT)/tools/Config_Handlers $(ACE_ROOT)/contrib/minizip + //to circumvent an improper include resolution + //in the Package_Handlers/PC_Intf.h + exename = RepositoryManagerDaemon + requires += zlib + after += minizip + libs += Package_Config_Handlers minizip + + IDL_Files { + RepositoryManagerDaemon.idl + } + + Source_Files { + RepositoryManagerDaemonC.cpp + RepositoryManagerDaemonS.cpp + ZIP_Wrapper.cpp + RepositoryManager.cpp + RepositoryManager_Impl.cpp + RM_Helper.cpp + URL_Parser.cpp + PC_Updater_T.cpp + PC_Updater.cpp + } + +} + + + +// RMadmin project: a sample client for the RM. + +project (RMAdmin) : ciao_servant_dnc, ciao_config_handlers, ciaoexe { + exename = RMadmin + after += RepositoryManager + + IDL_Files { + RepositoryManagerDaemon.idl + } + + Source_Files { + RMadmin.cpp + RepositoryManagerDaemonC.cpp + Options.cpp + RM_Helper.cpp + } +} diff --git a/CIAO/DAnCE/RepositoryManager/RepositoryManagerDaemon.idl b/CIAO/DAnCE/RepositoryManager/RepositoryManagerDaemon.idl new file mode 100644 index 00000000000..9deac4abd0e --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RepositoryManagerDaemon.idl @@ -0,0 +1,13 @@ +// $Id$ + +#include "DAnCE/Deployment/Deployment_RepositoryManager.idl" + +module CIAO +{ + interface RepositoryManagerDaemon : Deployment::RepositoryManager + { + // Shutdown the daemon process. + oneway void shutdown (); + }; +}; + diff --git a/CIAO/DAnCE/RepositoryManager/RepositoryManager_Impl.cpp b/CIAO/DAnCE/RepositoryManager/RepositoryManager_Impl.cpp new file mode 100644 index 00000000000..b3c86d5c221 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RepositoryManager_Impl.cpp @@ -0,0 +1,1226 @@ +// $Id$ + +//==================================================================== +/** + * @file RepositoryManager_Impl.cpp + * + * $Id$ + * + * Description: Actial implementation of the RepoMan + * + * @author Stoyan Paunov + * Shanshan Jiang <shanshan.jiang@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 +#include "ace/OS_Memory.h" //for ACE_NEW* macros + + +//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 + +//for the PackageConfiguration parsing +#include "DAnCE/Deployment/Deployment_DataC.h" +#include "DAnCE/Deployment/Deployment_Packaging_DataC.h" +#include "Package_Handlers/PCD_Handler.h" + +#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 "ace/Dirent.h" + +#include "URL_Parser.h" //for parsing the URL +#include "tao/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 "ace/Configuration_Import_Export.h" + +namespace +{ + static const char* PC_EXTENSION = ".epc"; + + static const char *RM_RECORD_FILE = "RM_record"; + static const char *RM_RECORD_NAME_SECTION = "Names"; + static const char *RM_RECORD_UUID_SECTION = "UUIDs"; +} + +//----------------------------------------------------------------- +//Constructor +// +//----------------------------------------------------------------- + +CIAO_RepositoryManagerDaemon_i::CIAO_RepositoryManagerDaemon_i + (CORBA::ORB_ptr the_orb, const char* server, const char* install_dir) + : the_orb_ (CORBA::ORB::_duplicate (the_orb)), + install_root_ (""), + HTTP_server_ ("http://"), + install_path (install_dir) +{ + //form the path + this->HTTP_server_ += server; + this->HTTP_server_ += "/"; + this->HTTP_server_ += install_path; + this->HTTP_server_ += "/"; + + //create directory in which the packages will be stored + ACE_OS::mkdir(install_path.c_str ()); + //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; + + // Install the configuration files to get the names, UUIDs, & types info. + ACE_Configuration_Heap cfg; + cfg.open (); + ACE_Configuration_Section_Key root = cfg.root_section (); + + ACE_Registry_ImpExp config_importer (cfg); + ACE_OS::chdir (install_path.c_str ()); + config_importer.import_config (RM_RECORD_FILE); + ACE_OS::chdir (this->cwd_); + + ACE_CString name; + ACE_Configuration::VALUETYPE type; + ACE_CString path; + + ACE_Configuration_Section_Key NameSection; + cfg.open_section (root, RM_RECORD_NAME_SECTION, 1, NameSection); + u_int index = 0; + while (!cfg.enumerate_values (NameSection, index, name, type)) + { + cfg.get_string_value (NameSection, name.c_str (), path); + this->names_.bind (name, path); + + ++index; + } + + ACE_Configuration_Section_Key UUIDSection; + cfg.open_section (root, RM_RECORD_UUID_SECTION, 1, UUIDSection); + index = 0; + while (!cfg.enumerate_values (UUIDSection, index, name, type)) + { + cfg.get_string_value (UUIDSection, name.c_str (), path); + this->uuids_.bind (name, path); + + ++index; + } + + // Add types + index = 0; + for (PCMap_Iterator iter = this->names_.begin (); + iter != this->names_.end (); + ++iter, ++index) + { + PCEntry& element = *iter; + + ::Deployment::PackageConfiguration_var pc = this->findPackageByName (element.ext_id_.c_str ()); + + if(!this->add_type (pc, element.ext_id_.c_str ())) + ACE_ERROR ((LM_ERROR, "Failed to add the type\n")); + } +} + +//----------------------------------------------------------------- +//Destructor +// +//----------------------------------------------------------------- + +CIAO_RepositoryManagerDaemon_i::~CIAO_RepositoryManagerDaemon_i (void) +{ + this->names_.unbind_all (); + this->uuids_.unbind_all (); + this->types_.unbind_all (); +} + +//----------------------------------------------------------------- +//shutdown +// +//----------------------------------------------------------------- + +void CIAO_RepositoryManagerDaemon_i::shutdown () + +{ + // Release resource. + this->names_.unbind_all (); + this->uuids_.unbind_all (); + this->types_.unbind_all (); + + this->the_orb_->shutdown (0); +} + + +//----------------------------------------------------------------- +//installPackage +// +//----------------------------------------------------------------- + +void CIAO_RepositoryManagerDaemon_i::installPackage ( + const char * installationName, + const char * location, + ::CORBA::Boolean replace + ) +{ + + PCEntry *entry = 0; + if (this->names_.find (ACE_CString (installationName), entry) == 0) + { + if (!replace) + throw Deployment::NameExists (); + else + deletePackage (installationName); + } + + //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 + + if (ACE_OS::strstr (location, "http://")) + { + + //TODO: how can I incorporate a Auto_Ptr is explicit release is needed + ACE_Message_Block* mb = 0; + ACE_NEW_THROW_EX (mb, ACE_Message_Block (), CORBA::NO_MEMORY ()); + + //get the remote file + if (!HTTP_Get (location, *mb)) + { + mb->release (); + throw CORBA::INTERNAL (); + } + + // Write file to designated location on disk + if (!RM_Helper::write_to_disk (package_path.c_str (), *mb)) + { + mb->release (); + throw CORBA::INTERNAL (); + } + + mb->release (); + } + else + { + if (!RM_Helper::copy_from_disk_to_disk (location, package_path.c_str ())) + throw CORBA::INTERNAL (); + } + + + 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 == "") + { + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + + 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 ()); + + + if (this->uuids_.find (ACE_CString (pc->UUID), entry) == 0) + { + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + + throw Deployment::NameExists (); + } + + //forming the server path info + ACE_CString server_path (this->HTTP_server_); + server_path += installationName; + + //NOTE: ComponentPackageReferences are currently NOT supported + if (!(pc->basePackage.length () > 0)) + { + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + + throw CORBA::NO_IMPLEMENT (); + } + + PC_Updater updater (server_path, package_path); + + if (!updater.update (pc)) + { + ACE_DEBUG ((LM_ERROR, "[RM] problem updating the PackageConfiguration!\n")); + + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + 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 + if (this->names_.bind (ACE_CString (installationName), path) == -1) + { + ACE_ERROR ((LM_ERROR, + "[RM] could not bind %s.\n", + installationName)); + + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + //remove the PackageConfiguration externalization + remove (pc_path.c_str ()); + + //throw exception + throw CORBA::INTERNAL (); + } + + //ALSO NEED THE UUID here + if (this->uuids_.bind (ACE_CString (pc->UUID), path) == -1) + { + ACE_ERROR ((LM_ERROR, + "[RM] could not bind %s.\n", + ACE_CString (pc->UUID).c_str ())); + + //unbind the name + this->names_.unbind (installationName); + + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + //remove the PackageConfiguration externalization + remove (pc_path.c_str ()); + + //throw exception + throw CORBA::INTERNAL (); + } + + //now add the type interface + if(!this->add_type (pc, installationName)) + ACE_ERROR ((LM_ERROR, "Failed to add the type\n")); + + this->dump (); + + this->save (); + + ACE_DEBUG ((LM_INFO, + "Installed PackageConfiguration \n\tname: %s \n\tuuid: %s\n", + installationName, ACE_CString (pc->UUID).c_str ())); +} + + +//----------------------------------------------------------------- +//createPackage +// +//----------------------------------------------------------------- + +void CIAO_RepositoryManagerDaemon_i::createPackage ( + const char * installationName, + const ::Deployment::PackageConfiguration & package, + const char * baseLocation, + ::CORBA::Boolean replace + ) +{ + ::Deployment::PackageConfiguration pc = package; + + // Find if there is a PackageConfiguration with the same name. + PCEntry *entry = 0; + if (this->names_.find (ACE_CString (installationName), entry) == 0) + { + if (!replace) + throw Deployment::NameExists (); + else + deletePackage (installationName); + } + + // Find if there is a PackageConfiguration with the same uuid. + if (this->uuids_.find (ACE_CString (pc.UUID), entry) == 0) + throw Deployment::NameExists (); + + // Find if the PackageConfiguration has a basePackage. + // NOTE: ComponentPackageReferences are currently NOT supported. + if (!(pc.basePackage.length () > 0)) + throw CORBA::NO_IMPLEMENT (); + + // Form the path for the local file + 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 + + // Check if URL or local file, download or load into memory + if (ACE_OS::strstr (baseLocation, "http://")) + { + //TODO: how can I incorporate a Auto_Ptr is explicit release is needed + ACE_Message_Block* mb; + ACE_NEW_THROW_EX (mb, ACE_Message_Block (), CORBA::NO_MEMORY ()); + + //get the remote file + if (!HTTP_Get (baseLocation, *mb)) + { + mb->release (); + throw CORBA::INTERNAL (); + } + + // Write file to designated location on disk + if (!RM_Helper::write_to_disk (package_path.c_str (), *mb)) + { + mb->release (); + throw CORBA::INTERNAL (); + } + + mb->release (); + } + else + { + if (!RM_Helper::copy_from_disk_to_disk (baseLocation, package_path.c_str ())) + throw CORBA::INTERNAL (); + } + + + ZIP_Wrapper::uncompress (const_cast<char*> (package_path.c_str ()), + const_cast<char*> (this->install_root_.c_str ()), + false //not verbose + ); + + // Form the server path info + ACE_CString server_path (this->HTTP_server_); + server_path += installationName; + + // Update the newly installed package configration informantion. + PC_Updater updater (server_path, package_path); + + if (!updater.update (pc)) + { + ACE_ERROR ((LM_ERROR, "[RM] problem updating the PackageConfiguration!\n")); + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + throw Deployment::PackageError (); + } + + // 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 name of the package. + if (this->names_.bind (ACE_CString (installationName), path) == -1) + { + ACE_ERROR ((LM_ERROR, + "[RM] could not bind %s.\n", + installationName)); + + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + //remove the PackageConfiguration externalization + remove (pc_path.c_str ()); + + //throw exception + throw CORBA::INTERNAL (); + } + + // Insert the UUID of the package. + if (this->uuids_.bind (ACE_CString (pc.UUID), path) == -1) + { + ACE_ERROR ((LM_ERROR, + "[RM] could not bind %s.\n", + ACE_CString (pc.UUID).c_str ())); + + //unbind the name + this->names_.unbind (installationName); + + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + //remove the PackageConfiguration externalization + remove (pc_path.c_str ()); + + //throw exception + throw CORBA::INTERNAL (); + } + + //now add the type interface + //TODO: CHECK if successful + if(!this->add_type (pc, installationName)) + ACE_ERROR ((LM_ERROR, "Failed to add the type\n")); + + this->dump (); + + this->save (); + + ACE_DEBUG ((LM_INFO, + "Created PackageConfiguration \n directory: %s \n name: %s \n uuid: %s\n", + path.c_str (), installationName, ACE_CString (pc.UUID).c_str ())); +} + + +//----------------------------------------------------------------- +//findPackageByName +// +//----------------------------------------------------------------- + +::Deployment::PackageConfiguration* +CIAO_RepositoryManagerDaemon_i::findPackageByName (const char * name) + +{ + // Find out if the PackageConfiguration was installed in the repository, + // return it if found or throw and exception otherwise + + PCEntry *entry = 0; + + if (this->names_.find (ACE_CString (name), entry) != 0) + throw Deployment::NoSuchName (); + //PackageConfiguration was not found + + ACE_CString pc_path (entry->int_id_.c_str ()); + pc_path += PC_EXTENSION; + + Deployment::PackageConfiguration_var pc; + ACE_NEW_THROW_EX (pc, + Deployment::PackageConfiguration (), + CORBA::NO_MEMORY ()); + + + if(!RM_Helper::reincarnate (pc, pc_path.c_str ())) + throw CORBA::INTERNAL (); + + ACE_DEBUG ((LM_INFO, "Successfully looked up \'%s\'.\n", name)); + + return pc._retn (); +} + + +//----------------------------------------------------------------- +//findPackageByUUID +// +//----------------------------------------------------------------- + +::Deployment::PackageConfiguration* +CIAO_RepositoryManagerDaemon_i::findPackageByUUID (const char * UUID) + +{ + // Find out if the PackageConfiguration was installed in the repository, + // return it if found or throw and exception otherwise + + PCEntry *entry = 0; + + if (this->uuids_.find (ACE_CString (UUID), entry) != 0) + throw Deployment::NoSuchName (); + //PackageConfiguration was not found + + ACE_CString pc_path (entry->int_id_.c_str ()); + pc_path += PC_EXTENSION; + + Deployment::PackageConfiguration_var pc; + ACE_NEW_THROW_EX (pc, + Deployment::PackageConfiguration (), + CORBA::NO_MEMORY ()); + + + if(!RM_Helper::reincarnate (pc, pc_path.c_str ())) + throw CORBA::INTERNAL (); + + ACE_DEBUG ((LM_INFO, "Successfully looked up %s.\n", UUID)); + + return pc._retn (); +} + +//----------------------------------------------------------------- +//findPackageByType +// +//----------------------------------------------------------------- + +::CORBA::StringSeq * CIAO_RepositoryManagerDaemon_i::findNamesByType ( + const char * type + ) +{ + CIEntry *entry = 0; + + //find the type in the interface map + if (this->types_.find (ACE_CString (type), entry) != 0) + { + //return an empty sequence + CORBA::StringSeq_var seq; + ACE_NEW_THROW_EX (seq, CORBA::StringSeq (0), CORBA::NO_MEMORY ()); + + return seq._retn (); + } + else + { + CISet ci_set = (*entry).int_id_set_; + + CORBA::ULong len = ci_set.size (); + + //allocate a sequence of the right length + CORBA::StringSeq_var seq; + ACE_NEW_THROW_EX (seq, + CORBA::StringSeq (len), + CORBA::NO_MEMORY ()); + seq->length (len); + + //store the elements in the string sequence + CISet_Iterator ci_set_iter (ci_set); + CORBA::ULong index = 0; + for (ci_set_iter = ci_set.begin (); + ci_set_iter != ci_set.end () && index < len; + ++ci_set_iter, ++index) + { + seq[index] = CORBA::string_dup ((*ci_set_iter).c_str ()); + } + + return seq._retn (); + } +} + + +//----------------------------------------------------------------- +//getAllNames +// +//----------------------------------------------------------------- + +::CORBA::StringSeq* +CIAO_RepositoryManagerDaemon_i::getAllNames () + +{ + //Map.current_size () gives you the current number with the duplicates + //Map.total_size () gives you the allocated space + the empty slots + //Apparently the only way to figure out the number of keys is to + //count them with an iterator. + + CORBA::ULong num_entries = 0; + + for (PCMap_Iterator i = this->names_.begin (); + i != this->names_.end (); + ++i) + ++num_entries; + + CORBA::StringSeq_var seq; + ACE_NEW_THROW_EX (seq, CORBA::StringSeq (num_entries), CORBA::NO_MEMORY ()); + + + seq->length (num_entries); + + CORBA::ULong index = 0; + for (PCMap_Iterator iter = this->names_.begin (); + iter != this->names_.end () && index < num_entries; + ++iter, ++index) + { + PCEntry& element = *iter; + seq[index] = CORBA::string_dup (element.ext_id_.c_str ()); + } + + ACE_DEBUG ((LM_INFO, "The number of packages %d\n", seq->length ())); + + return seq._retn (); //release the underlying CORBA::StringSeq +} + + +//----------------------------------------------------------------- +//getAllTypes +// +//----------------------------------------------------------------- + +::CORBA::StringSeq * CIAO_RepositoryManagerDaemon_i::getAllTypes ( + + ) +{ + //Map.current_size () gives you the current number with the duplicates + //Map.total_size () gives you the allocated space + the empty slots + //Apparently the only way to figure out the number of keys is to + //count them with an iterator. + + CORBA::ULong num_entries = 0; + + for (CIMap_Iterator i = this->types_.begin (); + i != this->types_.end (); + ++i) + ++num_entries; + + CORBA::StringSeq_var seq; + ACE_NEW_THROW_EX (seq, + CORBA::StringSeq (num_entries), + CORBA::NO_MEMORY ()); + + + seq->length (num_entries); + + CORBA::ULong index = 0; + for (CIMap_Iterator iter = this->types_.begin (); + iter != this->types_.end () && index < num_entries; + ++iter, ++index) + + { + CIEntry& element = *iter; + seq[index] = CORBA::string_dup (element.ext_id_.c_str ()); + } + + ACE_DEBUG ((LM_DEBUG, "The number of types: %d\n", num_entries)); + + return seq._retn (); //release the underlying CORBA::StringSeq +} + + +//----------------------------------------------------------------- +//DeletePackage +// +//----------------------------------------------------------------- + +void CIAO_RepositoryManagerDaemon_i::deletePackage ( + const char * installationName + ) +{ + bool internal_err = false; + + PCEntry *entry = 0; + + if (this->names_.find (ACE_CString (installationName), entry) != 0) + throw Deployment::NoSuchName (); + + //cache the package path + ACE_CString path (entry->int_id_.c_str ()); + + //remove the name association + if (this->names_.unbind (installationName) == -1) + { + ACE_ERROR ((LM_ERROR, + "Unable to unbind %s.\n", + installationName)); + internal_err = true; + } + + //the package location + ACE_CString package_path (path); + package_path += ".cpk"; //package extension + + //the PackageConfiguration externalization location + ACE_CString pc_path (path); + pc_path += PC_EXTENSION; //external PackageConfiguration extension + + Deployment::PackageConfiguration_var pc; + ACE_NEW_THROW_EX (pc, + Deployment::PackageConfiguration (), + CORBA::NO_MEMORY ()); + + + if(!RM_Helper::reincarnate (pc, pc_path.c_str ())) + { + ACE_ERROR ((LM_ERROR, "Could not reincarnate PC\n")); + internal_err = true; + } + + if (this->uuids_.unbind (ACE_CString (pc->UUID)) == -1) + { + ACE_ERROR ((LM_ERROR, "Could not remove UUID\n")); + internal_err = true; + } + + //remove the type from the interface map + if (!this->remove_type (pc, installationName)) + { + ACE_ERROR ((LM_ERROR, "Could not remove type\n")); + internal_err = true; + } + + //actually delete the package here! + + //clean the extracted files + remove_extracted_package (path.c_str ()); + //remove the package + remove (package_path.c_str ()); + //remove the PackageConfiguration externalization + remove (pc_path.c_str ()); + + this->dump (); + + this->save (); + + if (internal_err) + throw CORBA::INTERNAL (); + else + ACE_DEBUG ((LM_INFO, "Successfully deleted \'%s\'\n", installationName)); + +} + + +//==========================================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")); + throw CORBA::INTERNAL (); + } + + Deployment::PackageConfiguration_var pc; + //parse the PCD to make sure that there are no package errors + try + { + //CIAO::Config_Handlers::STD_PC_Intf intf (pcd_name.c_str ()); + //pc = intf.get_PC (); + } + catch (...) + { + ACE_ERROR ((LM_ERROR, + "(%P|%t) RepositoryManager: Error parsing the PCD\n")); + + //change back the the old working dir + ACE_OS::chdir (this->cwd_); + throw Deployment::PackageError (); + } + //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 retvieve a file via HTTP +//stores the file in the passed preallocated ACE_Message_Block +//returns 1 on success +// 0 on error + +int CIAO_RepositoryManagerDaemon_i::HTTP_Get (const char* URL, ACE_Message_Block &mb) +{ + URL_Parser *parser = TheURL_Parser::instance (); + if (!parser->parseURL (const_cast<char*> (URL))) + return 0; + + // Create a client + TAO_HTTP_Client client; + + // Open the client + if (client.open (parser->filename_, + parser->hostname_, + parser->port_) == -1) + { + client.close (); + return 0; + } + + // Read from it + if (client.read (&mb) <= 0) + { + client.close (); + return 0; + } + + return 1; +} + + + +//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 = new Deployment::PackageConfiguration (); + //parse the PCD to make sure that there are no package errors + try + { + CIAO::Config_Handlers::Packaging::PCD_Handler::package_config (pc_name, *pc); + } + catch (...) + { + 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_); + throw Deployment::PackageError (); + } + //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 + ACE_NEW_RETURN (file, ACE_Message_Block (0,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 remove file from disk!\n")); + return_code = 0; + } + } + //deallocate the head of the filename list + delete inf; + } + + return return_code; +} + +int CIAO_RepositoryManagerDaemon_i::remove_extracted_package (const char* path) + { + ACE_TCHAR full_path[MAXPATHLEN]; + ACE_OS::getcwd (full_path, sizeof(full_path)); + + ACE_OS::chdir (path); + + ACE_Dirent dir (path); + + for (ACE_DIRENT *directory; (directory = dir.read ()) != 0;) + { + if (ACE_OS::strcmp (directory->d_name, ".") == 0 + || ACE_OS::strcmp (directory->d_name, "..") == 0) + continue; + + ACE_stat stat_buf; + ACE_OS::lstat (directory->d_name, &stat_buf); + + ACE_CString temp = path; + temp += "/"; + temp += directory->d_name; + switch (stat_buf.st_mode & S_IFMT) + { + case S_IFREG: // Either a regular file or an executable. + remove (temp.c_str ()); + break; + + case S_IFDIR: + remove_extracted_package (temp.c_str ()); + break; + + default: + break; + } + } + + ACE_OS::chdir (full_path); + + ACE_OS::rmdir (path); + + return 0; + } + +//function to extract the type of the component from +//the PackageConfiguration and update the interface map +//returns 1 on success +// 0 on error + +int CIAO_RepositoryManagerDaemon_i::add_type (Deployment::PackageConfiguration& pc, + const char* name) +{ + if (pc.basePackage.length () > 0) + { + ::CORBA::StringSeq supportedTypes = pc.basePackage[0] + .implementation[0] + .referencedImplementation + .implements + .supportedType; + + if (supportedTypes.length () != 0) + { + CORBA::ULong len = supportedTypes.length (); + for (CORBA::ULong i = 0; i < len; ++i) + { + this->types_.bind (ACE_CString (supportedTypes[i]), name); + } + } + } + else //ComponentPackageReference + { + //not implemented yet + return 0; + } + + return 1; +} + +//function to remove the interface type of the component +//being removed from the interface map +//returns 1 on success +// 0 on error + +int CIAO_RepositoryManagerDaemon_i::remove_type (Deployment::PackageConfiguration& pc, + const char* name) +{ + if (pc.basePackage.length () > 0) + { + ::CORBA::StringSeq supportedTypes = pc.basePackage[0] + .implementation[0] + .referencedImplementation + .implements + .supportedType; + + if (supportedTypes.length () != 0) + { + CORBA::ULong len = supportedTypes.length (); + for (CORBA::ULong i = 0; i < len; ++i) + { + if (this->types_.unbind (ACE_CString (supportedTypes[i]), ACE_CString (name)) != 0) + ACE_DEBUG ((LM_DEBUG, "Could not find type %s with package name %s!\n", + ACE_CString (supportedTypes[i]).c_str (), + name)); + } + } + } + else //ComponentPackageReference + { + //not implemented yet + return 0; + } + + return 1; +} + +//function to dump the state of the RepositoryManager +void CIAO_RepositoryManagerDaemon_i::dump (void) +{ +#if defined (ACE_HAS_DUMP) + + ACE_DEBUG(LM_DEBUG, "NAMES:\n"); + this->names_.dump (); + ACE_DEBUG(LM_DEBUG, "UUIDs:\n"); + this->uuids_.dump (); + ACE_DEBUG (LM_DEBUG, "Component Interface Types:\n"); + this->types_.dump (); + +#endif /* ACE_HAS_DUMP */ +} + +//function to save the package info of the RepositoryManager +void CIAO_RepositoryManagerDaemon_i::save (void) +{ + // Save the names, UUIDs, & types info to the configuration files. + ACE_Configuration_Heap cfg; + cfg.open (); + ACE_Configuration_Section_Key root = cfg.root_section (); + + ACE_Configuration_Section_Key NameSection; + cfg.open_section (root, RM_RECORD_NAME_SECTION, 1, NameSection); + for (PCMap_Iterator iter = this->names_.begin (); + iter != this->names_.end (); + ++iter) + { + PCEntry& element = *iter; + cfg.set_string_value (NameSection, element.ext_id_.c_str (), element.int_id_.c_str ()); + } + + ACE_Configuration_Section_Key UUIDSection; + cfg.open_section (root, RM_RECORD_UUID_SECTION, 1, UUIDSection); + for (PCMap_Iterator iter = this->uuids_.begin (); + iter != this->uuids_.end (); + ++iter) + { + PCEntry& element = *iter; + cfg.set_string_value (UUIDSection, element.ext_id_.c_str (), element.int_id_.c_str ()); + } + + ACE_Registry_ImpExp exporter (cfg); + ACE_OS::chdir (install_path.c_str ()); + exporter.export_config (RM_RECORD_FILE); + ACE_OS::chdir (this->cwd_); +} diff --git a/CIAO/DAnCE/RepositoryManager/RepositoryManager_Impl.h b/CIAO/DAnCE/RepositoryManager/RepositoryManager_Impl.h new file mode 100644 index 00000000000..734ce8fc004 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/RepositoryManager_Impl.h @@ -0,0 +1,249 @@ + +/* -*- C++ -*- */ + +//====================================================================== +/** + * @file RepositoryManager_Impl.h + * + * $Id$ + * + * Description: + * This file is the main implementation file for the RepositoryManager + * in CIAO. We have used a number of techniques in order to increase + * scalability of the RepoMan while still maintaining complience with + * the D&C spec + * + * @author Stoyan Paunov + * Shanshan Jiang <shanshan.jiang@vanderbilt.edu> + */ +//====================================================================== + +#ifndef REPOSITORYMANAGERI_H_ +#define REPOSITORYMANAGERI_H_ + + +//-----------------------------NOTE--------------------------------- +//I need to disable all the code which has to do with interface +//type information because we currently do not support assembly +//interfaces which causes undesired behavior with respect to the +//hash tables because the specificType field in assembly interfaces +//is empty, so two unrelated intefaces appear to be related. + + +#include "RepositoryManagerDaemonS.h" + +#include "ace/Hash_Map_Manager_T.h" //for the ACE_Hash_Map_Manager +#include "ace/Hash_Multi_Map_Manager_T.h" //for the ACE_Hash_MultiMap_Manager +#include "ace/Null_Mutex.h" //for ACE_Null_Mutex +#include "ace/RW_Mutex.h" //for ACE_RW_Mutex +#include "ace/OS_NS_string.h" //for ACE_CString +#include "ace/SString.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace +{ + static const size_t TEMP_LEN = 1024; +} + +class CIAO_RepositoryManagerDaemon_i : + public virtual POA_CIAO::RepositoryManagerDaemon +{ +public: + /// Constructor + CIAO_RepositoryManagerDaemon_i (CORBA::ORB_ptr the_orb, + const char* server = "localhost:5432", + const char* install_dir = "RepositoryManager"); + + /// Destructor + virtual ~CIAO_RepositoryManagerDaemon_i (void); + + virtual + void shutdown ( + + ); + + virtual + void installPackage ( + const char * installationName, + const char * location, + ::CORBA::Boolean replace + ); + + virtual + void createPackage ( + const char * installationName, + const ::Deployment::PackageConfiguration & package, + const char * baseLocation, + ::CORBA::Boolean replace + ); + + virtual + ::Deployment::PackageConfiguration * findPackageByName ( + const char * name + ); + + virtual + ::Deployment::PackageConfiguration * findPackageByUUID ( + const char * UUID + ); + + virtual + ::CORBA::StringSeq * findNamesByType ( + const char * type + ); + + virtual + ::CORBA::StringSeq * getAllNames ( + + ); + + virtual + ::CORBA::StringSeq * getAllTypes ( + + ); + + virtual + void deletePackage ( + const char * installationName + ); + +protected: + + /// Function to parse and return the PackageConfiguration from a specified + /// package + Deployment::PackageConfiguration* retrieve_PC_from_package (char* package); + + /// Find out what the name of the PackageConfiguration file is + void find_PC_name (char* package, ACE_CString& pcd_name); + + /// Function to parse and return the PackageConfiguration from the already + /// extracted descriptor files + Deployment::PackageConfiguration* retrieve_PC_from_descriptors (const char* pc_name, + const char* descriptor_dir); + + + /// Function to retrieve a file via HTTP + /// stores the file in the passed preallocated ACE_Message_Block + /// @retval 1 success + /// @retval 0 error + int HTTP_Get (const char* URL, ACE_Message_Block &mb); + + /// Function to extract all necessary files for parsing the + /// PackageConfiguration descriptor and populating the idl struct. + /// @retval 1 success + /// @retval 0 error + /// + /// @note ACE_CString& pcd_name is an out parameter + int extract_descriptor_files (char* package, + ACE_CString& pcd_name); + + + /// Function to remove the files extracted for parsing the PackageConfiguration + /// descriptor and populating the idl struct. It reads the names of the files + /// from the package. They correspond to the names on disk. + /// @retval 1 on success + /// @retval 0 on error + int remove_descriptor_files (char* package); + + + /// 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. + /// @note extraction location is path/*archive_name*/ + /// @retval 1 on success + /// @retval 0 on error + int remove_extracted_package (const char* package_path); + + /// Function to extract the type of the component from + /// the PackageConfiguration and update the interface map + /// @retval 1 on success + /// @retval 0 on error + int add_type (::Deployment::PackageConfiguration& pc, + const char* name); + + /// Function to remove the interface type of the component + /// being removed from the interface map + /// @retval 1 on success + /// @retval 0 on error + int remove_type (::Deployment::PackageConfiguration& pc, + const char* name); + + /// Function to dump the state of the RepositoryManager + void dump (void); + + /// Function to save the package info of the RepositoryManager + void save (void); + +private: + /// Cached information about the installed PackageConfigurations + /// A separate map for the installation names and their UUID's + /// Key: PackageConfiguration name or its UUID (CString type) + /// Value: The location of the local copy of the package + + ///Based on the synchronization needed we can parametrize this with either + ///ACE_Null_Mutex or ACE_RW_Mutex + + typedef ACE_Hash_Map_Manager_Ex<ACE_CString, + ACE_CString, + ACE_Hash<ACE_CString>, + ACE_Equal_To<ACE_CString>, + ACE_RW_Mutex> PCMap; + + typedef PCMap::ITERATOR PCMap_Iterator; + typedef PCMap::ENTRY PCEntry; + + + /// Cached information about the installed Component Interfaces + /// A map which associates Component supportedType with the + /// names of packages which implement this component type + /// Key: Component supportedType + /// Value: Unbounded set of the names of installed packages which + /// implement this component type + + ///Based on the synchronization needed we can parametrize this with either + ///ACE_Null_Mutex or ACE_RW_Mutex + + typedef ACE_Hash_Multi_Map_Manager<ACE_CString, + ACE_CString, + ACE_Hash<ACE_CString>, + ACE_Equal_To<ACE_CString>, + ACE_RW_Mutex> CIMap; + + typedef CIMap::ITERATOR CIMap_Iterator; + typedef CIMap::ENTRY CIEntry; + typedef CIEntry::VALUE_SET CISet; + typedef CIEntry::VALUE_SET_ITERATOR CISet_Iterator; + + /// A hash map that associates the names of + /// PackageConfigurations with their location + PCMap names_; + + /// a hash map that associates the UUIDs of + /// PackageConfigurations with their location + PCMap uuids_; + + /// a hash map which associates Component Interface + /// UUIDs with their implementations + CIMap types_; + + /// The ORB + CORBA::ORB_var the_orb_; + + /// Will hold the current working directory + char cwd_ [TEMP_LEN]; + + /// Full path for the install directory + ACE_CString install_root_; + + /// Location of the server + ACE_CString HTTP_server_; + + /// Directory where the packages will be stored locally + ACE_CString install_path; +}; + +#endif /* REPOSITORYMANAGER_H_ */ diff --git a/CIAO/DAnCE/RepositoryManager/URL_Parser.cpp b/CIAO/DAnCE/RepositoryManager/URL_Parser.cpp new file mode 100644 index 00000000000..37187ebff61 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/URL_Parser.cpp @@ -0,0 +1,101 @@ +// $Id$ + +#include "ace/Get_Opt.h" +#include "ace/ARGV.h" +#include "URL_Parser.h" + +#include "ace/ACE.h" +#include "ace/OS_NS_string.h" + +bool +URL_Parser::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("rwu:h:p:f:d")); + + bool success = true; + int c; + + while ((c = get_opt ()) != -1) + switch (c) + { + case 'd': + this->debug_ = true; + break; + case 'u': + success = parseURL (get_opt.opt_arg ()); + break; + // Usage fallthrough. + default: + success = false; + } + + if (this->hostname_ == 0 || this->filename_ == 0) + { + success = false; + } + + return success; +} + +URL_Parser::URL_Parser (void) + : hostname_ (ACE::strnew ("127.0.0.1")), + port_ (ACE_DEFAULT_HTTP_SERVER_PORT), + filename_ (0), + debug_ (false) +{ +} + +bool URL_Parser::parseURL (char* url) +{ + char* ptr = 0; + bool success = true; + ptr = ACE_OS::strstr (url, "http://"); + if (ptr) + url += ACE_OS::strlen ("http://"); + + if (url[0] == '/') + { + this->filename_ = ACE_OS::strdup (url); + } + else + { + ptr = ACE_OS::strstr (url, ":"); + if (ptr) + this->port_ = ACE_OS::atoi (ptr + 1); + else + ptr = ACE_OS::strstr (url, "/"); + + if(!ptr) + success = false; + else + { + size_t host_len = ptr - url; + ACE::strdelete (this->hostname_); + ACE_NEW_RETURN (this->hostname_, char [host_len + 1], false); + ACE_OS::strncpy (this->hostname_, url, host_len); + this->hostname_ [host_len] = '\0'; + ptr = ACE_OS::strstr (ptr, "/"); + if (ptr) + { + this->filename_ = ACE_OS::strdup(ptr); + } + else + { + success = false; + } + } + } + return success; +} + + +void URL_Parser::Error (void) +{ + ACE_DEBUG ((LM_DEBUG, "./http_client -u http://hostname:port/filename [-d]\n")); +} + +URL_Parser::~URL_Parser() +{ + delete [] this->hostname_; + ACE_OS::free (this->filename_); +} diff --git a/CIAO/DAnCE/RepositoryManager/URL_Parser.h b/CIAO/DAnCE/RepositoryManager/URL_Parser.h new file mode 100644 index 00000000000..0dfef0262ad --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/URL_Parser.h @@ -0,0 +1,66 @@ + +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file URL_Parser.h + * + * $Id$ + * + * Parses a URL into its logical chunks + * + * @author Stoyan Paunov + */ +//============================================================================= + + +#ifndef URL_PARSER_H +#define URL_PARSER_H + +#include "ace/Get_Opt.h" +#include "ace/ARGV.h" +#include "ace/Singleton.h" //for ACE_Singleton +#include "ace/Null_Mutex.h" //for ACE_Null_Mutex + +// Forward declaration +class URL_Parser; + +typedef ACE_Singleton <URL_Parser, ACE_Null_Mutex> TheURL_Parser; + +class URL_Parser +{ +public: + + friend class ACE_Singleton <URL_Parser, ACE_Null_Mutex>; + + /// Parses commandline arguments + bool parse_args (int argc, ACE_TCHAR *argv[]); + + /// Return false on failure + bool parseURL (char* url); + + void Error (void); + + /// Hostname to connect to + ACE_TCHAR *hostname_; + + /// Port number to use + u_short port_; + + /// Filename to upload/download + ACE_TCHAR *filename_; + + /// Turns on verbosity + bool debug_; + + /// destructor + ~URL_Parser (void); + +protected: + /// protected constructor, singleton + URL_Parser (void); +}; + + + +#endif /* URL_PARSER_H */ diff --git a/CIAO/DAnCE/RepositoryManager/ZIP_Wrapper.cpp b/CIAO/DAnCE/RepositoryManager/ZIP_Wrapper.cpp new file mode 100644 index 00000000000..b318af0ad13 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/ZIP_Wrapper.cpp @@ -0,0 +1,375 @@ + +//=============================================================================== +/** + * @file ZIP_Wrapper.cpp + * + * $Id$ + * + * Purpose: implementing the ZIP_Wrapper class + * + * @author Stoyan Paunov, Vipul Singh + * + */ +//=============================================================================== + +#include "ace/Containers_T.h" //for ACE_Double_Linked_List +#include "ace/Message_Block.h" //for ACE_Message_Block +#include "ace/OS_NS_fcntl.h" //for open +#include "ace/OS_NS_unistd.h" //for close +#include "ace/OS_NS_string.h" //for strncpy +#include "ace/SString.h" //for ACE_CString +#include "ace/OS_NS_sys_stat.h" //for stat +#include "ace/OS_NS_sys_stat.h" //for filesize and mkdir +#include "ace/OS_Memory.h" //for ACE_NEW* macros + +#include <string> +#include "unzip.h" +#define MAXFILENAME (256) +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) + +#include "ZIP_Wrapper.h" + +//ZIP_File_Info constructor +ZIP_File_Info::ZIP_File_Info (char* name, size_t size) + : name_ (name), + size_ (size), + next_ (0), + prev_ (0) +{ +} + +//ZIP_File_Info default constructor +ZIP_File_Info::ZIP_File_Info () + : name_ (""), + size_ (0), + next_ (0), + prev_ (0) +{ +} + + +/// Gets a list of the files in the archive. +int ZIP_Wrapper::file_list_info (char* zip_name, + ACE_Double_Linked_List<ZIP_File_Info> &list) +{ + unzFile uf=0; + char filename_try[MAXFILENAME+16] = ""; + if (zip_name!=0) + { + strncpy(filename_try, zip_name, MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, if the string is too long. */ + filename_try[ MAXFILENAME ] = '\0'; + /* open the zip file */ + uf = unzOpen(zip_name); + /* if zipfile could not be opened, try appending .zip to name */ + if (uf==0) + { + ACE_OS::strcat(filename_try, ".zip"); + uf = unzOpen(filename_try); + } + } + /* If zipfile could not be opened still, return */ + if (uf==0) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("There is some problem in opening" + " %s or %s.zip using unzOpen \n"), zip_name, zip_name)); + return 1; + } + unz_global_info gi; + /* get information about all the files in zip file*/ + int err = unzGetGlobalInfo(uf, &gi); + if (err!=UNZ_OK) + ACE_DEBUG((LM_DEBUG, ACE_TEXT("unzGetGlobalInfo failed while trying" + " to get global information about zipfile \n"), err)); + /* gi.number_entry corresponds to the number of directory entries + in the zip file */ + for (uLong i=0;i<gi.number_entry;i++) + { + char filename_inzip[256]; + unz_file_info file_info; + /* get information about the current file in zip file */ + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, + sizeof(filename_inzip), 0, 0, 0, 0); + if (err!=UNZ_OK) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("unzGetCurrentFileInfo failed" + " while trying to get information" + " about current file\n"), err)); + break; + } + ZIP_File_Info* next = 0; + ACE_NEW_RETURN (next, ZIP_File_Info (filename_inzip, + sizeof(filename_inzip)), -1); + /* add information about current file to the list */ + list.insert_tail (next); + if ((i+1)<gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err!=UNZ_OK) + { + ACE_DEBUG((LM_DEBUG,ACE_TEXT(" unzGoToNextFile failed" + " while trying to go to next file\n"), err)); + break; + } + } + } + unzCloseCurrentFile(uf); + return gi.number_entry; +} + + +//get file and store it into ACE message block. +bool ZIP_Wrapper::get_file (char* archive_path, char* filename, + ACE_Message_Block &file) +{ + bool return_code = true; + unzFile uf=0; + uf = unzOpen(archive_path); + /* locate the desired file in the zip file and set it as current file*/ + int j=unzLocateFile(uf, filename, 0); + if (j==UNZ_END_OF_LIST_OF_FILE) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("File not found in zip archive"))); + return false; + } + else if (j==UNZ_OK) + { + int k=unzOpenCurrentFile(uf); + if (k!=UNZ_OK) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("Error in opening the current" + " file using unzOpenCurrentFile"))); + return false; + } + else + { + int num_read = 0; + ACE_Message_Block* head = &file; + + //read the file into the ACE_Message_Block + do + { + if (head->space () == 0) + { + ACE_Message_Block* next = 0; + ACE_NEW_RETURN (next, ACE_Message_Block (BUFSIZ), false); + head->cont (); + head = head->cont (); + } + num_read = unzReadCurrentFile(archive_path, head->wr_ptr(), + head->space()); + if (num_read > 0) + head->wr_ptr (num_read); + } while (num_read > 0); + if (num_read < 0) + return_code = false; + unzCloseCurrentFile(uf); + unzClose(uf); + return return_code; + } + } + return return_code; +} + + +/// uncompress the zip file +/// The zip file will be uncompressed into a directory +/// with the name of zip archive. +/// the path is assumed to be an existing directory + +bool ZIP_Wrapper::uncompress (char* zip_archive, char* path, bool verbose) +{ + //open the zip archive + unzFile uf=0; + uf = unzOpen(zip_archive); + if (uf==0) + { + ACE_DEBUG((LM_DEBUG,ACE_TEXT("unzOpen failed to open the" + " zipfile\n"))); + return false; + } + //get the name of the archive + ACE_CString arch_dir (path); + arch_dir += "/"; + //get only the name of the archive; remove path info + char* n = ACE_OS::strstr (zip_archive, "/"); + char* zip_name = 0; + while (n != 0) + { + zip_name = ++n; + n = ACE_OS::strstr (n, "/"); + } + arch_dir += zip_name; + //NOTE: Assumes .zip or cpk extension + arch_dir = arch_dir.substring (0, arch_dir.length () - 4); + //create directory with the name of zip archive + ACE_OS::mkdir(arch_dir.c_str()); + //if dir exists -1 is returned and ignored + unz_global_info gi; + int err = unzGetGlobalInfo(uf, &gi); + if (err!=UNZ_OK) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("unzGetGlobalInfo failed to get global" + " information about zipfile \n"), err)); + return false; + } + err =unzGoToFirstFile(uf); + if (err!=UNZ_OK) + { + ACE_DEBUG((LM_DEBUG,ACE_TEXT("error %d with zipfile in" + " unzGoToFirstFile \n"), err)); + return false; + } + /* read each entry of zip file, create directory structure if it is + a non existing directory whereas if it is a file, write the file + at the proper path in the directory structure */ + for (uLong i=0;i<gi.number_entry;i++) + { + char filename_inzip[256]; + unz_file_info file_info; + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, + sizeof(filename_inzip), 0, 0, 0, 0); + if (err!=UNZ_OK) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("unzGetCurrentFileInfo failed" + " while trying to get information" + " about currentfile\n"), err)); + break; + } + int direc = checkdir(filename_inzip); + /* If it is a directory, we create directory structure */ + if (direc==1) + { + makethedir(filename_inzip, arch_dir); + } + /* If it is a file, we read its data and write the uncompressed + data to the file with proper path.*/ + else if (direc==0) + { + handlethefile(filename_inzip, uf, file_info, verbose, arch_dir); + } + if ((i+1)<gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err!=UNZ_OK) + { + ACE_ERROR((LM_ERROR,ACE_TEXT("unzGoToNextFile failed" + " while trying to go to" + " nextfile\n"), err)); + break; + } + } + } + unzClose(uf); + return true; +} + + + +///try to find if it is a directory OR file +int ZIP_Wrapper::checkdir (char* filename_inzip) +{ + int direc = 0; + char* dircheck = ACE_OS::strstr (filename_inzip, "/"); + /* We assume that a directory will have its entry terminating in a / + We also assume that the directory entries in the zip file use + forward slash for both unix and windows */ + while (dircheck != 0) + { + int i = ACE_OS::strcmp(dircheck, "/"); + if (i == 0) + { + direc = 1; + break; + } + ++dircheck; + dircheck = ACE_OS::strstr (dircheck, "/"); + } + return direc; +} + +///Create directory structure if entry in zipfile is a directory +int ZIP_Wrapper::makethedir (char* filename_inzip, ACE_CString arch_dir) +{ +//let's try to create the directory structure for the package + char dir_name [2048]; + char* next = ACE_OS::strstr (filename_inzip, "/"); + while (next != 0) + { + ACE_CString location (arch_dir); + ACE_OS::strncpy (dir_name, filename_inzip, next - filename_inzip + + 1); + + dir_name[next - filename_inzip + 1] = '\0'; + location += "/"; + location += dir_name; + ACE_stat stat; + if (ACE_OS::stat (location.c_str (), &stat) == -1) + ACE_OS::mkdir (location.c_str ()); + next++; + next = ACE_OS::strstr (next, "/"); + } + return 0; +} + +///If entry in zipfile is a file, then read the file and write the +///uncompressed data at the proper filepath. +int ZIP_Wrapper::handlethefile (char* filename_inzip, unzFile uf, + unz_file_info file_info, bool verbose, + ACE_CString arch_dir) +{ + int k = unzOpenCurrentFile(uf); + if (k!=UNZ_OK) + { + ACE_ERROR((LM_ERROR,ACE_TEXT("unzOpenCurrentFile failed in" + " opening the current file"))); + return false; + } + else + { + size_t const file_size = file_info.uncompressed_size; + char* temp = 0; + ACE_NEW_RETURN (temp, char [file_size], false); + ACE_Auto_Basic_Array_Ptr<char> buffer (temp); + //read in the data + unzReadCurrentFile(uf, &(*buffer), file_size); + //close the zip handle + unzCloseCurrentFile(uf); + //create file name + path to open + std::string file_path (arch_dir.c_str ()); + //NOTE: need the c-style char to stop at '\0' + file_path += "/"; + file_path += filename_inzip; + //print out the file to be uncompressed + if (verbose) + { + ACE_OS::write(ACE_STDOUT, file_path.c_str (), + file_path.length () ); + ACE_OS::write(ACE_STDOUT, "\n", 1); + } + // Open a file handle to the local filesystem + ACE_HANDLE handle = ACE_OS::open (file_path.c_str (), + O_CREAT | O_TRUNC | O_WRONLY); + if (handle == ACE_INVALID_HANDLE) + { + unzClose(uf); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[uncompress] file creation error")), + 0); + } + //write the uncompressed data to the file + if (ACE_OS::write (handle, &(*buffer), file_size) == -1) + { + unzClose(uf); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("[uncompress] file write error")), + 0); + } + // Close the file handle + ACE_OS::close (handle); + } + return 0; +} diff --git a/CIAO/DAnCE/RepositoryManager/ZIP_Wrapper.h b/CIAO/DAnCE/RepositoryManager/ZIP_Wrapper.h new file mode 100644 index 00000000000..918a60f6352 --- /dev/null +++ b/CIAO/DAnCE/RepositoryManager/ZIP_Wrapper.h @@ -0,0 +1,117 @@ + +/* -*- C++ -*- */ + +//======================================================================= +/** + * @file ZIP_Wrapper.h + * + * $Id$ + * + * Purpose: to provide a wrapper around minizip for easy handling of + * ZIP archives. This wrapper can be used as an auxiliary + * class that allows a program to become ZIP-aware + * + * @author Stoyan Paunov, Vipul Singh + * + * + */ +//======================================================================= + +#ifndef _ZIP_WRAPPER_H_ +#define _ZIP_WRAPPER_H_ + +#include "ace/Containers_T.h" //for ACE_Double_Linked_List +#include "ace/Message_Block.h" //for ACE_Message_Block +#include "ace/SString.h" //for ACE_CString +#include "ace/Log_Msg.h" +#include "ace/Synch.h" +#include "ace/OS_NS_fcntl.h" //for open +#include "ace/OS_NS_sys_stat.h" //for filesize and mkdir + +#include "unzip.h" + + +/** + * @class ZIP_File_Info + * + * This class is used as a carrier of information + * about entities residing inside a ZIP archive + */ +class ZIP_File_Info +{ +public: + ACE_CString name_; + size_t size_; + ZIP_File_Info* next_; + ZIP_File_Info* prev_; + + ZIP_File_Info (char* name, size_t size); + ZIP_File_Info (); +}; + +/** + * @class ZIP_Wrappers + * + * This class is the actual workhorse that provides all of + * the necessary functionality + */ +class ZIP_Wrapper +{ +public: + + /// Get file and store it into an ACE_Message_Block. The function + /// averts subdirectory traversal problems. + /// NOTE: Be sure to release the message block even if the function returns + /// false becuase the return value might be due to unsuccessful allocation + + ///archive_path is the zip archive with the path + ///filename is the name of the file to be looked for in the zip archive. + ///the file is stored in ACE message block. + static bool get_file (char* archive_path, char* filename, + ACE_Message_Block &file); + + /// uncompress the zip file + /// The zip file will be uncompressed into a directory with the + ///name of zip archive. + /// The path is assumed to be an existing directory + + ///zip_archive is the arcive to be uncompressed with full path. + ///path is used for creating a directory with the name of zip archive. + static bool uncompress (char* zip_archive, char* path = "", + bool verbose = true); + + /// Get a list of the files in the archive + + ///zip_name is the name of zipfile with fullpath. + ///list stores information about each entry in zip file. + static int file_list_info (char* zip_name, + ACE_Double_Linked_List<ZIP_File_Info> &list); + + ///Check if an entry of a zip file is a file or directory + ///We assume a directoryname terminates with a forward slash + ///Returns 1 for directory while 0 for file. + + ///filename_inzip is an entry in a zipfile + static int checkdir (char* filename_inzip); + + ///Create directory structure if entry in zipfile is a directory + + ///filename_inzip is an entry in a zipfile + ///arch_dir stores the name of the directory to be created + static int makethedir (char* filename_inzip, ACE_CString arch_dir); + + ///If entry in zipfile is a file, then read the file and write + /// the uncompressed data at the proper filepath. + + ///filename_inzip is an entry in a zipfile + ///uf refers to the zip archive + ///file_info is used to get information about current file + ///verbose decides if the details are to be printed or not + ///arch_dir is the name of file with full path where it is to be + ///uncompressed + static int handlethefile (char* filename_inzip, unzFile uf, + unz_file_info file_info, + bool verbose, ACE_CString arch_dir); +}; + +#endif |