diff options
author | Ossama Othman <ossama-othman@users.noreply.github.com> | 2000-06-21 22:54:25 +0000 |
---|---|---|
committer | Ossama Othman <ossama-othman@users.noreply.github.com> | 2000-06-21 22:54:25 +0000 |
commit | c489facc3cbe2292a7edc78920d6d316b9250a65 (patch) | |
tree | 8d91b9d20428fdeda025b5d46255de4b8cc440cb /TAO/examples/Content_Server | |
parent | faa66c456d64718a1a4080f40126842b16da1f59 (diff) | |
download | ATCD-c489facc3cbe2292a7edc78920d6d316b9250a65.tar.gz |
ChangeLogTag:Wed Jun 21 15:51:10 2000 Ossama Othman <ossama@uci.edu>
Diffstat (limited to 'TAO/examples/Content_Server')
27 files changed, 454 insertions, 593 deletions
diff --git a/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.cpp b/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.cpp index 5aefbf685b8..8b253015f81 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.cpp +++ b/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.cpp @@ -6,7 +6,7 @@ #include "ace/FILE_Connector.h" #include "Content_Iterator_i.h" -ACE_RCSID(AMI_Iterator, Content_Iterator_i, "$Id$") +ACE_RCSID (AMI_Iterator, Content_Iterator_i, "$Id$") Content_Iterator_i::Content_Iterator_i (const char *pathname, CORBA::ULong file_size) diff --git a/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.h b/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.h index 607ee9a9d5f..e85a263dcfa 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.h +++ b/TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.h @@ -5,7 +5,7 @@ // ============================================================================ // // = LIBRARY -// ECE255 +// AMI_Iterator // // = FILENAME // Content_Iterator_i.h @@ -32,28 +32,36 @@ class Content_Iterator_i : public virtual POA_Web_Server::Content_Iterator, public virtual PortableServer::RefCountServantBase - // = TITLE - //Implement the Web_Server::Content_Iterator interface. { + // = TITLE + // Implement the Web_Server::Content_Iterator interface. + // + // = DESCRIPTION + // This class implements the Iterator pattern to minimize memory + // requirements when retrieving data from a content server. + // Rather than retrieving one large chunk of data, this class + // iterates on the server so that smaller chunks of data are + // retrieved. + friend class Iterator_Factory_i; public: - // Constructor Content_Iterator_i (const char *filename, CORBA::ULong file_size); + // Constructor - // Destructor ~Content_Iterator_i (void); + // Destructor - // This operation returns the next <chunk> of the file starting at - // <offset>. If there are no more bindings, false is returned. virtual CORBA::Boolean next_chunk (CORBA::ULong offset, Web_Server::Chunk_Type_out chunk, CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException)); + // This operation returns the next <chunk> of the file starting at + // <offset>. If there are no more bindings, false is returned. - // Destroy the iterator. virtual void destroy (CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException)); + // Destroy the iterator. private: diff --git a/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.cpp b/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.cpp index 32e2c07d1ba..6ea2ce3711a 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.cpp +++ b/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.cpp @@ -6,7 +6,7 @@ #include "Content_Iterator_i.h" #include "Iterator_Factory_i.h" -ACE_RCSID(AMI_Iterator, Iterator_Factory_i, "$Id$") +ACE_RCSID (AMI_Iterator, Iterator_Factory_i, "$Id$") void Iterator_Factory_i::get_iterator (const char *pathname, @@ -15,8 +15,6 @@ Iterator_Factory_i::get_iterator (const char *pathname, CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException, Web_Server::Error_Result)) { - // Based on code available in H&V. - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Received request for file: <%s>\n"), pathname)); @@ -26,8 +24,12 @@ Iterator_Factory_i::get_iterator (const char *pathname, // HTTP 1.1 "Internal Server Error". ACE_THROW (Web_Server::Error_Result (500)); - Content_Iterator_i *iterator_servant = - new Content_Iterator_i (pathname, file_status.st_size); + Content_Iterator_i *iterator_servant = 0; + ACE_NEW_THROW_EX (iterator_servant, + Content_Iterator_i (pathname, + file_status.st_size), + CORBA::NO_MEMORY ()); + ACE_CHECK; if (iterator_servant->init () != 0) { @@ -45,7 +47,13 @@ Iterator_Factory_i::get_iterator (const char *pathname, iterator_servant->_this (ACE_TRY_ENV); ACE_CHECK; - metadata = new Web_Server::Metadata_Type; + Web_Server::Metadata_Type *tmp = 0; + ACE_NEW_THROW_EX (tmp, + Web_Server::Metadata_Type, + CORBA::NO_MEMORY ()); + ACE_CHECK; + + metadata = tmp; if (this->modification_date (&file_status, metadata) != 0) diff --git a/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.h b/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.h index 69b3fa995b9..9111434603d 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.h +++ b/TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.h @@ -4,7 +4,7 @@ // ============================================================================ // // = LIBRARY -// ECE255 +// AMI_Iterator // // = FILENAME // Iterator_Factory_i.h @@ -34,28 +34,33 @@ class Content_Iterator_i; class Iterator_Factory_i : virtual public POA_Web_Server::Iterator_Factory { // = TITLE - // Implement the Web_Server::Iterator_Factory interface. + // Factory that creates a Content_Iterator that retrieves fixed + // size chunks of data from Content server. + // + // = DESCRIPTION + // This class creates a Content_Iterator that is set up to + // iteratively download a specific file. This same factory can + // be used to create Content_Iterators for other files. public: - // This factory method returns a <Content_Iterator> that can be used - // to read the <contents> associated with <pathname> one ``chunk'' - // at a time. The <metadata> reports information about the - // <contents>. virtual void get_iterator (const char *pathname, Web_Server::Content_Iterator_out contents, Web_Server::Metadata_Type_out metadata, CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException, Web_Server::Error_Result)); + // This factory method returns a <Content_Iterator> that can be used + // to read the <contents> associated with <pathname> one ``chunk'' + // at a time. The <metadata> reports information about the + // <contents>. - // Set the file modification date in the metadata structure. int modification_date (struct stat *file_status, Web_Server::Metadata_Type_out metadata); + // Set the file modification date in the metadata structure. - // Set the type of file content in the metadata structure. int content_type (const char *filename, Web_Server::Metadata_Type_out metadata); - + // Set the type of file content in the metadata structure. }; #endif /* ITERATOR_FACTORY_I_H */ diff --git a/TAO/examples/Content_Server/AMI_Iterator/Iterator_Handler.h b/TAO/examples/Content_Server/AMI_Iterator/Iterator_Handler.h index 4b653122a89..5d3755b2c0c 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/Iterator_Handler.h +++ b/TAO/examples/Content_Server/AMI_Iterator/Iterator_Handler.h @@ -4,7 +4,7 @@ // ============================================================================ // // = LIBRARY -// Content_Server +// AMI_Iterator // // = FILENAME // Iterator_Handler.h @@ -21,8 +21,6 @@ #ifndef ITERATOR_HANDLER_H #define ITERATOR_HANDLER_H -#include "ace/pre.h" - #include "ace/FILE_Addr.h" #include "ace/FILE_IO.h" #include "Web_ServerS.h" @@ -31,14 +29,25 @@ # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ -// Dummy class to quiet down a warning. -class Iterator_Handler_Friend; class Iterator_Handler : public virtual POA_Web_Server::AMI_Content_IteratorHandler, public virtual PortableServer::RefCountServantBase { - friend Iterator_Handler_Friend; + // = TITLE + // The AMI reply handler for replies from the Content_Iterator. + // + // = DESCRIPTION + // This class handles all asynchronously received replies from + // the Content_Iterator on the server side. Once a reply is + // handled, another asynchronous request is made to the + // Content_Iterator. This ensures that chunks of data are + // received in the proper order, and also takes advantage of + // asyncronous method invocations. + + friend class Iterator_Handler_Friend; + // Dummy friend class declaration to quiet down a warning. + public: Iterator_Handler (void); @@ -73,6 +82,7 @@ public: // pointer itself) of the <request_count> parameter will be // incremented when file retrieval begins, and decremented when file // retrieval completes. + private: ~Iterator_Handler (void); // Destructor (private to ensure that Iterator_Handler is allocated @@ -126,6 +136,4 @@ private: // decremented when file retrieval has completed. }; -#include "ace/post.h" - #endif /* ITERATOR_HAHNDLER_H */ diff --git a/TAO/examples/Content_Server/AMI_Iterator/client.cpp b/TAO/examples/Content_Server/AMI_Iterator/client.cpp index 65ab63ee97c..179a392d48b 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/client.cpp +++ b/TAO/examples/Content_Server/AMI_Iterator/client.cpp @@ -8,7 +8,7 @@ #include "Web_ServerC.h" #include "Iterator_Handler.h" -ACE_RCSID(AMI_Iterator, client, "$Id") +ACE_RCSID (AMI_Iterator, client, "$Id$") // Obtain reference to Iterator_Factory Web_Server::Iterator_Factory_ptr @@ -55,7 +55,7 @@ main (int argc, char *argv[]) mgr->activate (ACE_TRY_ENV); ACE_TRY_CHECK; - // Now narrow to an Iterator_Factory reference. + // Get an Iterator_Factory reference. Web_Server::Iterator_Factory_var factory = ::get_iterator (orb.in (), ACE_TRY_ENV); @@ -137,7 +137,7 @@ get_iterator (CORBA::ORB_ptr o, ACE_CHECK_RETURN (Web_Server::Iterator_Factory::_nil ()); // Narrow to a Naming Context - CosNaming::NamingContext_var nc = + CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); ACE_CHECK_RETURN (Web_Server::Iterator_Factory::_nil ()); @@ -182,7 +182,7 @@ void invoke_requests (int argc, Iterator_Handler, CORBA::NO_MEMORY ()); ACE_CHECK; - + // Transfer ownership to the POA. PortableServer::ServantBase_var tmp (handler); diff --git a/TAO/examples/Content_Server/AMI_Iterator/server.cpp b/TAO/examples/Content_Server/AMI_Iterator/server.cpp index e6a1262a669..3db1745290b 100644 --- a/TAO/examples/Content_Server/AMI_Iterator/server.cpp +++ b/TAO/examples/Content_Server/AMI_Iterator/server.cpp @@ -8,7 +8,7 @@ #include "Iterator_Factory_i.h" -ACE_RCSID(AMI_Iterator, server, "$Id$") +ACE_RCSID (AMI_Iterator, server, "$Id$") int main (int argc, char *argv[]) @@ -51,7 +51,7 @@ main (int argc, char *argv[]) ACE_TRY_CHECK; // Narrow to a Naming Context - CosNaming::NamingContext_var nc = + CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); ACE_TRY_CHECK; diff --git a/TAO/examples/Content_Server/AMI_Observer/Callback.cpp b/TAO/examples/Content_Server/AMI_Observer/Callback.cpp deleted file mode 100644 index 6e473ea41ba..00000000000 --- a/TAO/examples/Content_Server/AMI_Observer/Callback.cpp +++ /dev/null @@ -1,296 +0,0 @@ -// -*- C++ -*- -// $Id$ - -// Ossama Othman <ossama@uci.edu> - -#include "ace/FILE_Connector.h" -#include "ace/Log_Msg.h" -#include "ace/Process_Manager.h" -#include "ace/Synch.h" -#include "Callback.h" - -ACE_RCSID(AMI_Observer, Callback, "$Id$") - -Callback_i::Callback_i (int *request_count) - : file_ (ACE_sap_any_cast (ACE_FILE_Addr &)), - file_io_ (), - ami_handler_ (), - metadata_ (), - last_chunk_ (0), - lock_ (), - request_count_ (request_count) -{ - // Create a temporary file to store the retrieved data. - ACE_FILE_Connector connector; - - if (connector.connect (this->file_io_, - this->file_, - 0, - ACE_Addr::sap_any, - 0, - O_CREAT | O_TRUNC | O_WRONLY, - S_IRUSR | S_IWUSR) == -1) - { - ACE_ERROR ((LM_ERROR, - ACE_TEXT ("%p\n"), - ACE_TEXT ("Could not open file %s"), - this->file_.get_path_name ())); - } - else - (*this->request_count_)++; -} - -Callback_i::~Callback_i (void) -{ - (void) this->file_io_.close (); -} - -void -Callback_i::next_chunk (const Web_Server::Chunk_Type & chunk_data, - CORBA::Boolean last_chunk, - CORBA::Environment &ACE_TRY_ENV) - ACE_THROW_SPEC ((CORBA::SystemException)) -{ - if (!last_chunk) - { - Web_Server::Chunk_Type_var chunk = chunk_data; - - // Append the received data to the corresponding - // buffer/temporary file. - if (this->file_io_.send (chunk->get_buffer (), - chunk->length ()) == -1) - { - (*this->request_count_)--; // Don't wait for more data. - - ACE_ERROR ((LM_ERROR, - ACE_TEXT ("%p\n"), - ACE_TEXT ("Unable to write retrieved data to ") - ACE_TEXT ("file <%s>"), - this->file_.get_path_name ())); - return; - } - } - else - { - { - ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, - guard, - this->lock_)); - - this->last_chunk_ = 1; // Received entire content. - } - - ACE_DEBUG ((LM_INFO, - ACE_TEXT ("Wrote retrieved data to file <%s>\n"), - this->file_.get_path_name ())); - - (*this->request_count_)--; // No more data. - - // File retrieval has completed, so spawn an external viewer to - // display its contents. - - // If the entire metadata has been received, then spawn an - // external viewer to display the received file. - if (this->metadata_received ()) - { - (void) this->file_io_.close (); - this->deactivate (ACE_TRY_ENV); - ACE_CHECK; - - (void) this->spawn_viewer (); - } - } -} - -void -Callback_i::metadata (const Web_Server::Metadata_Type &metadata) -{ - ACE_DECLARE_NEW_CORBA_ENV; - ACE_TRY - { - { - ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, - guard, - this->lock_)); - this->metadata_ = metadata; - } - - ACE_DEBUG ((LM_INFO, - ACE_TEXT ("Retrieved file has the following ") - ACE_TEXT ("characteristics:\n") - ACE_TEXT (" Modification Date: %s\n") - ACE_TEXT (" Content Type: %s\n"), - this->metadata_.modification_date.in (), - this->metadata_.content_type.in ())); - - // If the entire content of the data has been received, then spawn - // an external viewer to display it. - if (this->content_received ()) - { - this->deactivate (ACE_TRY_ENV); - ACE_TRY_CHECK; - - (void) this->spawn_viewer (); - } - } - ACE_CATCHANY - { - ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, - ACE_TEXT ("Caught unexpected exception ") - ACE_TEXT ("in Callback_i::metdata(...):")); - } - ACE_ENDTRY; -} - -int -Callback_i::metadata_received (void) -{ - ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, - guard, - this->lock_, - 0)); - - return (this->metadata_.content_type.in () != 0); -} - -int -Callback_i::content_received (void) -{ - ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, - guard, - this->lock_, - 0)); - - return this->last_chunk_; -} - -int -Callback_i::get_viewer (char *viewer, - size_t length) -{ - const char *content_type = - this->metadata_.content_type.in (); - - if (ACE_OS::strcasecmp (content_type, "text/html") == 0) - { - const char lynx[] = "lynx"; - if (length <= sizeof (lynx)) - return -1; - else - ACE_OS::strcpy (viewer, lynx); - } - else if (ACE_OS::strcasecmp (content_type, - "text/plain") == 0) - { - const char more[] = "more"; - if (length <= sizeof (more)) - return -1; - else - ACE_OS::strcpy (viewer, more); - } - else if (ACE_OS::strcasecmp (content_type, - "application/postscript") == 0) - { - const char ghostview[] = "ghostview"; - if (length <= sizeof (ghostview)) - return -1; - else - ACE_OS::strcpy (viewer, ghostview); - } - else if (ACE_OS::strcasecmp (content_type, - "application/pdf") == 0) - { - const char acroread[] = "acroread"; - if (length <= sizeof (acroread)) - return -1; - else - ACE_OS::strcpy (viewer, acroread); - } - else if (ACE_OS::strcasecmp (content_type, - "image/jpeg") == 0 - || ACE_OS::strcasecmp (content_type, - "image/gif") == 0 - || ACE_OS::strcasecmp (content_type, - "image/tiff") == 0 - || ACE_OS::strcasecmp (content_type, - "image/png") == 0) - { - const char xv[] = "xv"; - if (length <= sizeof (xv)) - return -1; - else - ACE_OS::strcpy (viewer, xv); - } - else - ACE_ERROR_RETURN ((LM_ERROR, - "Unsupported MIME type: <%s>\n", - content_type), - -1); - - return 0; -} - -int -Callback_i::spawn_viewer (void) -{ - // It is highly unlikey, a mime type will ever be larger than 80 - // bytes. - char viewer[80]; - - if (this->get_viewer (viewer, - sizeof (viewer)) != 0) - ACE_ERROR_RETURN ((LM_ERROR, - ACE_TEXT ("Problem determining which external ") - ACE_TEXT ("viewer to use.\n")), - -1); - - // Set up the command line that will be used when spawning the - // external viewer. - ACE_Process_Options opts; - opts.command_line (ACE_TEXT ("%s %s"), - viewer, - this->file_.get_path_name ()); - - pid_t result = ACE_Process_Manager::instance ()->spawn (opts); - - switch (result) - { - case 0: - // Child - return 0; - case ACE_INVALID_PID: - ACE_ERROR_RETURN ((LM_ERROR, - ACE_TEXT ("%p\n"), - ACE_TEXT ("Error during viewer spawn of ") - ACE_TEXT ("\"%s\""), - opts.command_line_buf ()), - -1); - default: - // Parent - ACE_DEBUG ((LM_INFO, - "Spawned viewer <%s> with PID <%d>.\n", - viewer, - result)); - break; - } - - return 0; -} - -void -Callback_i::deactivate (CORBA::Environment &ACE_TRY_ENV) -{ - // Get the POA used when activating the Reply Handler object. - PortableServer::POA_var poa = this->_default_POA (ACE_TRY_ENV); - ACE_CHECK; - - // Get the object ID associated with this servant. - PortableServer::ObjectId_var oid = - poa->servant_to_id (this, - ACE_TRY_ENV); - ACE_CHECK; - - // Now deactivate the iterator object. - poa->deactivate_object (oid.in (), ACE_TRY_ENV); - ACE_CHECK; -} diff --git a/TAO/examples/Content_Server/AMI_Observer/Callback.h b/TAO/examples/Content_Server/AMI_Observer/Callback.h deleted file mode 100644 index c6c230494f1..00000000000 --- a/TAO/examples/Content_Server/AMI_Observer/Callback.h +++ /dev/null @@ -1,108 +0,0 @@ -// -*- C++ -*- -// $Id$ - -// ============================================================================ -// -// = LIBRARY -// Content_Server -// -// = FILENAME -// Callback.h -// -// = DESCRIPTION -// Header file for the Web_Server::Callback implementation. -// -// = AUTHOR -// Ossama Othman <ossama@uci.edu> -// -// ============================================================================ - -#ifndef CALLBACK_H -#define CALLBACK_H - -#include "ace/pre.h" - -#include "ace/FILE_Addr.h" -#include "ace/FILE_IO.h" -#include "Push_Web_ServerS.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -// Implement the Web_Server::Callback interface. -class Callback_i : - public virtual POA_Web_Server::Callback, - public virtual PortableServer::RefCountServantBase -{ -public: - Callback_i (int *request_count); - // Constructor - - virtual void next_chunk (const Web_Server::Chunk_Type &chunk, - CORBA::Boolean last_chunk, - CORBA::Environment &ACE_TRY_ENV) - ACE_THROW_SPEC ((CORBA::SystemException)); - // This operation returns the next <chunk> of the file starting at - // <offset>. If there are no more bindings, false is returned. - - void metadata (const Web_Server::Metadata_Type &metadata); - // Set metadata associated with received data. - -private: - - ~Callback_i (void); - // Destructor must be private to ensure that this object is - // allocated on the heap. - - int metadata_received (void); - // Returns one if the metadata was received, and zero otherwise. - - int content_received (void); - // Returns one if the entire content was received, and zero - // otherwise. - - int get_viewer (char *viewer, size_t length); - // Get the name of the viewer associated with the file being - // retrieved. - - int spawn_viewer (void); - // Spawn an external view to display the retrieved file. - -private: - - void deactivate (CORBA::Environment &ACE_TRY_ENV); - // Deactivate this Callback servant. - -private: - - ACE_FILE_Addr file_; - // The Addr corresponding to the retrieved file. - - ACE_FILE_IO file_io_; - // The object that provides all file related IO operations - // (e.g. read, write, etc). - - Web_Server::AMI_CallbackHandler_var ami_handler_; - // Reference to this Reply Handler's self. - - Web_Server::Metadata_Type metadata_; - // The metadata associated with the file being retrieved from the - // web server. - - int last_chunk_; - // Flag that indicates entire data content has been received. - - ACE_SYNCH_MUTEX lock_; - // Lock used to prevent race conditions when checking to see if - // metadata or entire content has been received. - - int *request_count_; - // Pointer to external status monitoring variable. The contents (not - // the pointer itself) of the <pending_data> parameter will be - // decremented when file retrieval has completed. -}; - -#include "ace/post.h" - -#endif /* CONTENT_ITERATOR_I_H */ diff --git a/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.cpp b/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.cpp index 0172273b0d3..0ecfbdf5dbb 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.cpp +++ b/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.cpp @@ -7,7 +7,7 @@ #include "ace/Log_Msg.h" #include "Callback_Handler.h" -ACE_RCSID(AMI_Observer, Callback_Handler, "$Id$") +ACE_RCSID (AMI_Observer, Callback_Handler, "$Id$") Callback_Handler::Callback_Handler (const char *pathname, Web_Server::Callback_ptr client_callback) @@ -43,6 +43,9 @@ Callback_Handler::next_chunk (CORBA::Environment &ACE_TRY_ENV) CORBA::Octet *buf = Web_Server::Chunk_Type::allocbuf (BUFSIZ); + if (buf == 0) + ACE_THROW (CORBA::NO_MEMORY ()); + ssize_t bytes_read = this->file_io_.recv (buf, BUFSIZ); if (bytes_read == -1) @@ -82,7 +85,7 @@ Callback_Handler::next_chunk (CORBA::Environment &ACE_TRY_ENV) } void -Callback_Handler::next_chunk_excep +Callback_Handler::next_chunk_excep (Web_Server::AMI_CallbackExceptionHolder *excep_holder, CORBA::Environment &) ACE_THROW_SPEC ((CORBA::SystemException)) @@ -107,26 +110,24 @@ Callback_Handler::next_chunk_excep ACE_ENDTRY; } -ACE_HANDLE +void Callback_Handler::run (CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException, Web_Server::Error_Result)) { // Open the file to be downloaded this->open_file (ACE_TRY_ENV); - ACE_CHECK_RETURN (ACE_INVALID_HANDLE); + ACE_CHECK; // Activate this Reply Handler. this->ami_handler_ = this->_this (ACE_TRY_ENV); - ACE_CHECK_RETURN (ACE_INVALID_HANDLE); + ACE_CHECK; // Begin the asynchronous invocation. Note that the AMI // "sendc_next_chunk()" call is done within the following call, // since data must first be read into the Chunk. this->next_chunk (ACE_TRY_ENV); - ACE_CHECK_RETURN (ACE_INVALID_HANDLE); - - return this->file_io_.get_handle (); + ACE_CHECK; } void diff --git a/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.h b/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.h index 85686a24cee..5639ad94853 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.h +++ b/TAO/examples/Content_Server/AMI_Observer/Callback_Handler.h @@ -4,7 +4,7 @@ // ============================================================================ // // = LIBRARY -// Content_Server +// AMI_Observer // // = FILENAME // Callback_Handler.h @@ -35,6 +35,45 @@ class Callback_Handler : public virtual POA_Web_Server::AMI_CallbackHandler, public virtual PortableServer::RefCountServantBase { + // = TITLE + // Class that asynchronously sends chunks of data to the + // client-side <Callback> object, and handles all asynchronous + // replies emanating from it. + // + // = DESCRIPTION + // The <Push_Iterator_Factory_i> object in the Content Server + // creates a <Callback_Handler> instance for each requested file, + // and executes the run() method in that instance (in this + // class). To allow the Content Server to service other requests + // without having to wait for the requested file to be completely + // sent to the client, the run() method in this class issues the + // next_chunk() method, which reads the first chunk of data and + // sends it asynchronously to the client-side <Callback> object + // by issuing a sendc_next_chunk() call. + // + // This may seem a bit odd since the next_chunk() method in this + // class is actually the reply handler method for the + // sendc_next_chunk() method. The next_chunk() method is + // initially invoked as a means to bootstrap the process of + // asynchronously sending chunks of data to the client-side + // <Callback> object. However, since the next_chunk() method + // actually invokes sendc_next_chunk(), all subsequent calls will + // be performed asynchronously. This design also guarantees that + // the client-side <Callback> object will receive all chunks of + // data in the proper order since the next chunk of data will not + // be sent until this <Callback_Handler> receives the asynchronous + // reply from the client-side <Callback> object. Again, that + // asynchronous reply is handled by the next_chunk() method, at + // which point the entire cycle is started again until the last + // chunk of data is sent. + // + // Notice that no threads are explicitly created at the + // application level, yet concurrency is achieved due to the fact + // that all operations are performed asynchronously. + + friend class Callback_Handler_Friend; + // Dummy friend class declaration to quiet down a warning. + public: Callback_Handler (const char *pathname, Web_Server::Callback_ptr callback); @@ -49,7 +88,7 @@ public: CORBA::Environment &) ACE_THROW_SPEC ((CORBA::SystemException)); - ACE_HANDLE run (CORBA::Environment &ACE_TRY_ENV) + void run (CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException, Web_Server::Error_Result)); // Activate and run this Reply Handler. The contents (not the diff --git a/TAO/examples/Content_Server/AMI_Observer/Callback_i.cpp b/TAO/examples/Content_Server/AMI_Observer/Callback_i.cpp index 6e473ea41ba..a0b0ac452ef 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Callback_i.cpp +++ b/TAO/examples/Content_Server/AMI_Observer/Callback_i.cpp @@ -7,9 +7,9 @@ #include "ace/Log_Msg.h" #include "ace/Process_Manager.h" #include "ace/Synch.h" -#include "Callback.h" +#include "Callback_i.h" -ACE_RCSID(AMI_Observer, Callback, "$Id$") +ACE_RCSID (AMI_Observer, Callback_i, "$Id$") Callback_i::Callback_i (int *request_count) : file_ (ACE_sap_any_cast (ACE_FILE_Addr &)), @@ -168,7 +168,7 @@ int Callback_i::get_viewer (char *viewer, size_t length) { - const char *content_type = + const char *content_type = this->metadata_.content_type.in (); if (ACE_OS::strcasecmp (content_type, "text/html") == 0) @@ -223,7 +223,7 @@ Callback_i::get_viewer (char *viewer, } else ACE_ERROR_RETURN ((LM_ERROR, - "Unsupported MIME type: <%s>\n", + ACE_TEXT ("Unsupported MIME type: <%s>\n"), content_type), -1); @@ -233,9 +233,7 @@ Callback_i::get_viewer (char *viewer, int Callback_i::spawn_viewer (void) { - // It is highly unlikey, a mime type will ever be larger than 80 - // bytes. - char viewer[80]; + char viewer[BUFSIZ]; if (this->get_viewer (viewer, sizeof (viewer)) != 0) diff --git a/TAO/examples/Content_Server/AMI_Observer/Callback_i.h b/TAO/examples/Content_Server/AMI_Observer/Callback_i.h index c6c230494f1..0faeccd12be 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Callback_i.h +++ b/TAO/examples/Content_Server/AMI_Observer/Callback_i.h @@ -4,10 +4,10 @@ // ============================================================================ // // = LIBRARY -// Content_Server +// AMI_Observer // // = FILENAME -// Callback.h +// Callback_i.h // // = DESCRIPTION // Header file for the Web_Server::Callback implementation. @@ -17,8 +17,8 @@ // // ============================================================================ -#ifndef CALLBACK_H -#define CALLBACK_H +#ifndef CALLBACK_I_H +#define CALLBACK_I_H #include "ace/pre.h" @@ -35,6 +35,27 @@ class Callback_i : public virtual POA_Web_Server::Callback, public virtual PortableServer::RefCountServantBase { + // = TITLE + // Implement the Web_Server::Callback interface. + // + // = DESCRIPTION + // A <Callback> object implements the Observer pattern. It + // simply "watches" while the Content Server pushes chunks of + // data to itself. Once the Content Server pushes the last chunk + // of data, the <Callback> object spawns an external viewer to + // display the pushed data based on the data content type + // returned by the Iterator_Factory::register_callback() method. + // + // Since the server pushes data to the <Callback> object + // asynchronously, and since instances of this <Callback> class + // are registered with the Content Server asynchronously, there + // is no guarantee that the metadata containing the content type + // will arrive before the content of the file. As such, this + // class atomically sets and checks the flags that provide the + // current condition of the metadata and content, in case two + // concurrently running threads attempt to update the state + // contained within a given <Callback> object. + public: Callback_i (int *request_count); // Constructor @@ -105,4 +126,4 @@ private: #include "ace/post.h" -#endif /* CONTENT_ITERATOR_I_H */ +#endif /* CALLBACK_I_H */ diff --git a/TAO/examples/Content_Server/AMI_Observer/Makefile b/TAO/examples/Content_Server/AMI_Observer/Makefile index d9c232c9488..b5c1359a201 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Makefile +++ b/TAO/examples/Content_Server/AMI_Observer/Makefile @@ -1,7 +1,6 @@ +# # $Id$ # -# Makefile for ECE 255 Web Server -- Assignment 4 -# Ossama Othman <ossama@uci.edu> #---------------------------------------------------------------------------- @@ -23,7 +22,7 @@ SERVER_FILES = \ server CLIENT_FILES = \ - Callback \ + Callback_i \ Push_Iterator_Handler \ client @@ -1052,7 +1051,7 @@ realclean: clean $(ACE_ROOT)/ace/FILE.i \ $(ACE_ROOT)/ace/FILE_IO.i -.obj/Callback.o .obj/Callback.so .shobj/Callback.o .shobj/Callback.so: Callback.cpp \ +.obj/Callback_i.o .obj/Callback_i.so .shobj/Callback_i.o .shobj/Callback_i.so: Callback_i.cpp \ $(ACE_ROOT)/ace/FILE_Connector.h \ $(ACE_ROOT)/ace/pre.h \ $(ACE_ROOT)/ace/FILE_IO.h \ @@ -1152,8 +1151,8 @@ realclean: clean $(ACE_ROOT)/ace/Reactor_Impl.h \ $(ACE_ROOT)/ace/Process.h \ $(ACE_ROOT)/ace/Process.i \ - $(ACE_ROOT)/ace/Process_Manager.i Callback.h \ - Push_Web_ServerS.h \ + $(ACE_ROOT)/ace/Process_Manager.i \ + Callback_i.h Push_Web_ServerS.h \ $(TAO_ROOT)/tao/MessagingS.h \ $(TAO_ROOT)/tao/orbconf.h \ $(TAO_ROOT)/tao/TimeBaseS.h \ @@ -1694,7 +1693,7 @@ realclean: clean $(TAO_ROOT)/tao/BoundsC.h \ $(TAO_ROOT)/tao/BoundsC.i \ Push_Web_ServerC.i Push_Web_ServerS_T.h Push_Web_ServerS_T.i \ - Push_Web_ServerS_T.cpp Push_Web_ServerS.i Callback.h \ + Push_Web_ServerS_T.cpp Push_Web_ServerS.i Callback_i.h \ $(ACE_ROOT)/ace/FILE_Addr.h \ $(ACE_ROOT)/ace/Addr.h \ $(ACE_ROOT)/ace/Addr.i \ diff --git a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.cpp b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.cpp index 1667618cf4d..73ef258aea8 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.cpp +++ b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.cpp @@ -6,10 +6,10 @@ #include "Push_Iterator_Factory_i.h" #include "Callback_Handler.h" -ACE_RCSID(AMI_Observer, Push_Iterator_Factory_i, "$Id$") +ACE_RCSID (AMI_Observer, Push_Iterator_Factory_i, "$Id$") Web_Server::Metadata_Type * -Push_Iterator_Factory_i::register_callback +Push_Iterator_Factory_i::register_callback (const char *pathname, Web_Server::Callback_ptr client_callback, CORBA::Environment &ACE_TRY_ENV) @@ -27,7 +27,7 @@ Push_Iterator_Factory_i::register_callback // content. ACE_DEBUG ((LM_DEBUG, - "Received request for file: <%s>\n", + ACE_TEXT ("Received request for file: <%s>\n"), pathname)); // Send the file to the client asynchronously. This allows the @@ -42,34 +42,42 @@ Push_Iterator_Factory_i::register_callback // Transfer ownership to the POA. PortableServer::ServantBase_var tmp (handler); - ACE_HANDLE fd = handler->run (ACE_TRY_ENV); + // Start sending data to the client callback object. + handler->run (ACE_TRY_ENV); ACE_CHECK_RETURN (0); struct stat file_status; - if (fd == ACE_INVALID_HANDLE - || ACE_OS::fstat (fd, - &file_status) == -1) + if (ACE_OS::stat (pathname, + &file_status) == -1) // HTTP 1.1 "Internal Server Error". ACE_THROW_RETURN (Web_Server::Error_Result (500), 0); - Web_Server::Metadata_Type_var metadata = - new Web_Server::Metadata_Type; + + Web_Server::Metadata_Type *meta_tmp = 0; + ACE_NEW_THROW_EX (meta_tmp, + Web_Server::Metadata_Type, + CORBA::NO_MEMORY ()); + ACE_CHECK_RETURN (0); + + Web_Server::Metadata_Type_var metadata = meta_tmp; if (this->modification_date (&file_status, metadata.inout ()) != 0) // HTTP 1.1 "Internal Server Error. ACE_THROW_RETURN (Web_Server::Error_Result (500), 0); + if (this->content_type (pathname, metadata.inout ()) != 0) // HTTP 1.1 "Internal Server Error. ACE_THROW_RETURN (Web_Server::Error_Result (500), 0); + return metadata._retn (); } int -Push_Iterator_Factory_i::modification_date +Push_Iterator_Factory_i::modification_date (struct stat *file_status, Web_Server::Metadata_Type & metadata) { @@ -154,9 +162,9 @@ Push_Iterator_Factory_i::content_type (const char *filename, { metadata.content_type = CORBA::string_dup ("text/html"); ACE_ERROR ((LM_WARNING, - "\n " - "Unknown file type. " - "Using \"text/html\" content type.\n")); + ACE_TEXT ("\n ") + ACE_TEXT ("Unknown file type. ") + ACE_TEXT ("Using \"text/html\" content type.\n"))); } return 0; diff --git a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.h b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.h index d6a51ad2e9d..aba6d9e3535 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.h +++ b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.h @@ -5,7 +5,7 @@ // ============================================================================ // // = LIBRARY -// Content_Server +// AMI_Observer // // = FILENAME // Push_Iterator_Factory_i.h @@ -35,9 +35,22 @@ class Push_Iterator_Factory_i : virtual public POA_Web_Server::Iterator_Factory { // = TITLE - // Implement the Web_Server::Iterator_Factory interface. + // Implement the Web_Server::Iterator_Factory interface. + // + // = DESCRIPTION + // This class is used to register a client-side <Callback> object + // with the Content Server, which is actually implemented by the + // <Callback_Handler> class for each requested file. + // + // The client invokes the register_callback() method in this + // class. That method then creates a <Callback_Handler> which + // will push chunks of data asynchronously to the client-side + // <Callback> object. This allows the Content Server to + // concurrently service multiple file requests without the need + // to explicitly use threads at the application level. + public: - Web_Server::Metadata_Type *register_callback + Web_Server::Metadata_Type *register_callback (const char *pathname, Web_Server::Callback_ptr client_callback, CORBA::Environment &ACE_TRY_ENV) diff --git a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.cpp b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.cpp index 778cf94d274..4cf2a709de5 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.cpp +++ b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.cpp @@ -6,9 +6,9 @@ #include "ace/Log_Msg.h" #include "ace/Process_Manager.h" #include "Push_Iterator_Handler.h" -#include "Callback.h" +#include "Callback_i.h" -ACE_RCSID(AMI_Observer, Push_Iterator_Handler, "$Id$") +ACE_RCSID (AMI_Observer, Push_Iterator_Handler, "$Id$") Push_Iterator_Handler::Push_Iterator_Handler (void) : callback_servant_ (0), @@ -24,7 +24,7 @@ Push_Iterator_Handler::~Push_Iterator_Handler (void) } void -Push_Iterator_Handler::register_callback +Push_Iterator_Handler::register_callback (const Web_Server::Metadata_Type &metadata, CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException)) diff --git a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.h b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.h index bae26e065f0..87eb65fafe7 100644 --- a/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.h +++ b/TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.h @@ -1,12 +1,10 @@ // -*- C++ -*- // $Id$ -// Ossama Othman <ossama@uci.edu> - // ============================================================================ // // = LIBRARY -// ECE255 +// AMI_Observer // // = FILENAME // Push_Iterator_Handler.h @@ -37,6 +35,29 @@ class Push_Iterator_Handler : public virtual POA_Web_Server::AMI_Iterator_FactoryHandler, public virtual PortableServer::RefCountServantBase { + // = TITLE + // Implement the Web_Server::Iterator_Factory AMI Reply Handler. + // + // = DESCRIPTION + // This classes asynchronously registers a reference to the + // client-side <Callback> object in the Content Server. Once + // registered, the <Callback> will begin receiving chunks of data + // pushed from the Content Server. + // + // Since registration occurs asynchronously, it is possible that + // the metadata returned from the <Iterator_Factory> will be + // received after the content of the file has been received. The + // <Callback> object is equipped to handle this possibility. + // + // The register_callback() reply handler method in this class + // receives the metadata, and then passes it to the <Callback> + // object. Once the metadata is received, there is no longer any + // use for this <Push_Iterator_Handler> object, and it is + // deactivated. + + friend class Push_Iterator_Handler_Friend; + // Dummy friend class declaration to quiet down a warning. + public: Push_Iterator_Handler (void); // Constructor that creates a content iterator corresponding to the @@ -66,7 +87,7 @@ private: // AMI callback that is invoked when a response from the // corresponding server method is received. - virtual void register_callback_excep + virtual void register_callback_excep (Web_Server::AMI_Iterator_FactoryExceptionHolder *, CORBA::Environment &) ACE_THROW_SPEC ((CORBA::SystemException)) {} diff --git a/TAO/examples/Content_Server/AMI_Observer/README b/TAO/examples/Content_Server/AMI_Observer/README index 8c5d635dcb2..f9e4de33b5d 100644 --- a/TAO/examples/Content_Server/AMI_Observer/README +++ b/TAO/examples/Content_Server/AMI_Observer/README @@ -14,7 +14,66 @@ is as follows: * The CORBA Naming Service is used to bind and resolve object references, rather than using a file. - + + +Basic design of the programs: + +The basic idea used in both the client and and the server is to use +AMI when performing all requests. This allows both the client and the +server to perform other tasks without having to wait for a given task +to complete. + +The client first activates its Callback object, and then +asynchronously registers a reference to its Callback object with the +server's Push_Iterator_Factory. The Push_Iterator_Factory then +creates an AMI reply handler "Callback_Handler" for the requested file +that asynchronously sends chunks of data to the client's Callback +object. After creating and running the Callback_Handler, the +Push_Iterator_Factory returns the Metadata containing the content type +and modification date of the file to client. Since the Callback was +registered using the Push_Iterator_Factory using AMI, an AMI reply +handler called "Push_Iterator_Handler" on the client side will receive +and handle the Metadata returned from the Push_Iterator_Factory. The +Push_Iterator_Handler then passes the received Metadata to the +Callback object. The Callback will spawn an external viewer once both +the Metadata and the entire file content have been received. The +Callback object is designed to correctly handle the case where the +content is received before the Metadata, and vice versa. This +operation is thread-safe. Note that no threads are created at the +application level in neither the client nor the server, yet +concurrency is still achieved due to the fact that AMI is used on both +sides. + +A schematic of the operations involved follows: + + CLIENT SERVER + ------ ------ + Push_Iterator_Handler - activate + Callback - activate Push_Iterator_Factory - activate + + sendc_register_callback() ---> register_callback() + Callback_Handler - activate + + next_chunk() <--- sendc_next_chunk() + . . + . . + . . + next_chunk() <--- sendc_next_chunk() + + register_callback() <--- Metadata - returned + Metadata passed to Callback + + next_chunk() <--- sendc_next_chunk() + . . + . . + . . + next_chunk() <--- sendc_next_chunk() + +Note that the Callback_Handler will not send the next chunk until it +receives a reply from the client's Callback object. This ensures that +the client receives all chunks of data in the proper order. + + The client program performs the following activities: 1. From the command-line, it reads the name of the pathname @@ -25,10 +84,10 @@ The client program performs the following activities: object reference for a CosNaming::NamingContext interface, which is then used to resolve the object reference that the server bound earlier. After narrowing this to the Server - interface, the register_callback() operation is called via - the object reference to pass the Callback interface from - the client to the server, which then uses AMI to push - chunks of the file to the client. + interface, the sendc_register_callback() operation is + called via the object reference to pass asynchronously pass + the Callback interface from the client to the server, which + then uses AMI to push chunks of the file to the client. 2. The server calls the sendc_next_chunk() method on the callback, passing in the offset and the next chunk. @@ -40,6 +99,7 @@ The client program performs the following activities: viewer is spawned to display the file. The type of viewer to spawn is determined by examining the the content_type_ metadata returned by the server. + The example can be run as follows: diff --git a/TAO/examples/Content_Server/AMI_Observer/client.cpp b/TAO/examples/Content_Server/AMI_Observer/client.cpp index 53cfc089aeb..f81d307bc7f 100644 --- a/TAO/examples/Content_Server/AMI_Observer/client.cpp +++ b/TAO/examples/Content_Server/AMI_Observer/client.cpp @@ -8,7 +8,19 @@ #include "Push_Web_ServerC.h" #include "Push_Iterator_Handler.h" -ACE_RCSID(AMI_Observer, client, "$Id$") +ACE_RCSID (AMI_Observer, client, "$Id$") + +// Obtain reference to Iterator_Factory +Web_Server::Iterator_Factory_ptr +get_iterator (CORBA::ORB_ptr orb, + CORBA::Environment &ACE_TRY_ENV); + +// Perform file requests +void invoke_requests (int argc, + char *argv[], + int *request_count, + Web_Server::Iterator_Factory_ptr f, + CORBA::Environment &ACE_TRY_ENV); int main (int argc, char *argv[]) @@ -18,7 +30,8 @@ main (int argc, char *argv[]) { if (argc < 2) ACE_ERROR_RETURN ((LM_ERROR, - "Usage: client filename [filename ...]\n"), + ACE_TEXT ("Usage: client filename ") + ACE_TEXT ("[filename ...]\n")), -1); // Initialize the ORB. @@ -43,40 +56,18 @@ main (int argc, char *argv[]) mgr->activate (ACE_TRY_ENV); ACE_TRY_CHECK; - // Get a reference to the Name Service. - obj = orb->resolve_initial_references ("NameService", - ACE_TRY_ENV); - ACE_TRY_CHECK; - - // Narrow to a Naming Context - CosNaming::NamingContext_var nc = - CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); - ACE_TRY_CHECK; - - if (CORBA::is_nil (obj.in ())) - { - ACE_ERROR_RETURN ((LM_ERROR, - "Nil reference to Name Service\n"), - -1); - } - - // Create a name. - CosNaming::Name name; - name.length (1); - name[0].id = CORBA::string_dup ("Push_Iterator_Factory"); - name[0].kind = CORBA::string_dup (""); - - obj = nc->resolve (name, ACE_TRY_ENV); + // Get an Iterator_Factory reference. + Web_Server::Iterator_Factory_var factory = + ::get_iterator (orb.in (), + ACE_TRY_ENV); ACE_TRY_CHECK; - // Now narrow to an Iterator_Factory reference. - Web_Server::Iterator_Factory_var factory = - Web_Server::Iterator_Factory::_narrow (obj.in ()); if (CORBA::is_nil (factory.in ())) { ACE_ERROR_RETURN ((LM_ERROR, - "Object pointed to by:\n %s\n" - "is not an Iterator_Factory object.\n", + ACE_TEXT ("Object pointed to by:\n %s\n") + ACE_TEXT ("is not an Iterator_Factory") + ACE_TEXT ("object.\n"), argv[1]), -1); } @@ -86,24 +77,12 @@ main (int argc, char *argv[]) int request_count = 0; // Activate and run the reply handlers. - for (int i = 0; - i < argc - 1; // Don't include the program name. - ++i) - { - Push_Iterator_Handler *handler = 0; - ACE_NEW_RETURN (handler, - Push_Iterator_Handler, - -1); - - // Transfer ownership to the POA. - PortableServer::ServantBase_var tmp_handler (handler); - - handler->run (&request_count, - argv[i + 1], - factory.in (), - ACE_TRY_ENV); - ACE_TRY_CHECK; - } + ::invoke_requests (argc, + argv, + &request_count, + factory.in (), + ACE_TRY_ENV); + ACE_TRY_CHECK; // 1 millisecond delay to reduce "busy waiting" in ORB event // loop. @@ -131,14 +110,15 @@ main (int argc, char *argv[]) ACE_CATCH (Web_Server::Error_Result, exc) { ACE_ERROR_RETURN ((LM_ERROR, - "Caught Web Server exception with status %d\n", + ACE_TEXT ("Caught Web Server exception ") + ACE_TEXT ("status %d\n"), exc.status), -1); } ACE_CATCHANY { ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, - "Caught unexpected exception:"); + ACE_TEXT ("Caught unexpected exception:")); return -1; } @@ -149,3 +129,74 @@ main (int argc, char *argv[]) return 0; } + +Web_Server::Iterator_Factory_ptr +get_iterator (CORBA::ORB_ptr o, + CORBA::Environment &ACE_TRY_ENV) +{ + CORBA::ORB_var orb = CORBA::ORB::_duplicate (o); + + // Get a reference to the Name Service. + CORBA::Object_var obj = + orb->resolve_initial_references ("NameService", + ACE_TRY_ENV); + ACE_CHECK_RETURN (Web_Server::Iterator_Factory::_nil ()); + + // Narrow to a Naming Context + CosNaming::NamingContext_var nc = + CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); + ACE_CHECK_RETURN (Web_Server::Iterator_Factory::_nil ()); + + if (CORBA::is_nil (obj.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Nil reference to Name Service\n"))); + return Web_Server::Iterator_Factory::_nil (); + } + + // Create a name. + CosNaming::Name name; + name.length (1); + name[0].id = CORBA::string_dup ("Push_Iterator_Factory"); + name[0].kind = CORBA::string_dup (""); + + obj = nc->resolve (name, ACE_TRY_ENV); + ACE_CHECK_RETURN (Web_Server::Iterator_Factory::_nil ()); + + Web_Server::Iterator_Factory_ptr factory = + Web_Server::Iterator_Factory::_narrow (obj.in ()); + + return factory; +} + +void invoke_requests (int argc, + char *argv[], + int *request_count, + Web_Server::Iterator_Factory_ptr f, + CORBA::Environment &ACE_TRY_ENV) +{ + Web_Server::Iterator_Factory_var factory = + Web_Server::Iterator_Factory::_duplicate (f); + + // Activate and run the reply handlers. + for (int i = 0; + i < argc - 1; // Don't include the program name. + ++i) + { + Push_Iterator_Handler *handler = 0; + ACE_NEW_THROW_EX (handler, + Push_Iterator_Handler, + CORBA::NO_MEMORY ()); + ACE_CHECK; + + // Transfer ownership to the POA. + PortableServer::ServantBase_var tmp (handler); + + // This ends up being an AMI call, so it won't block. + handler->run (request_count, + argv[i + 1], + factory.in (), + ACE_TRY_ENV); + ACE_CHECK; + } +} diff --git a/TAO/examples/Content_Server/AMI_Observer/server.cpp b/TAO/examples/Content_Server/AMI_Observer/server.cpp index 5fa713faf6e..501b2db71d9 100644 --- a/TAO/examples/Content_Server/AMI_Observer/server.cpp +++ b/TAO/examples/Content_Server/AMI_Observer/server.cpp @@ -7,7 +7,7 @@ #include "Push_Web_ServerS.h" #include "Push_Iterator_Factory_i.h" -ACE_RCSID(AMI_Observer, server, "$Id$") +ACE_RCSID (AMI_Observer, server, "$Id$") int main (int argc, char *argv[]) @@ -49,7 +49,7 @@ main (int argc, char *argv[]) ACE_TRY_CHECK; // Narrow to a Naming Context - CosNaming::NamingContext_var nc = + CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); ACE_TRY_CHECK; @@ -67,12 +67,12 @@ main (int argc, char *argv[]) ACE_TRY_ENV); ACE_TRY_CHECK; ACE_DEBUG ((LM_DEBUG, - "Bound <%s> to <%s> in Name Service.\n", + ACE_TEXT ("Bound <%s> to <%s> in Name Service.\n"), name[0].id.in (), IOR.in ())); ACE_DEBUG ((LM_INFO, - "Accepting requests.\n")); + ACE_TEXT ("Accepting requests.\n"))); // Accept requests. orb->run (ACE_TRY_ENV); @@ -81,7 +81,7 @@ main (int argc, char *argv[]) ACE_CATCHANY { ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, - "Caught unexpected exception:"); + ACE_TEXT ("Caught unexpected exception:")); return -1; } diff --git a/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.cpp b/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.cpp index e82359ff97a..428cf5cee73 100644 --- a/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.cpp +++ b/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.cpp @@ -27,11 +27,17 @@ Content_Iterator_i::~Content_Iterator_i (void) CORBA::Boolean Content_Iterator_i::next_chunk (CORBA::ULong offset, Web_Server::Chunk_Type_out chunk, - CORBA::Environment &) + CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException)) { // Initialize/allocate the Chunk_Type sequence - chunk = new Web_Server::Chunk_Type; + Web_Server::Chunk_Type *tmp = 0; + ACE_NEW_THROW_EX (tmp, + Web_Server::Chunk_Type, + CORBA::NO_MEMORY ()); + ACE_CHECK_RETURN (0); + + chunk = tmp; if (offset >= this->file_size_) return 0; // Applications shouldn't throw system exceptions. diff --git a/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.h b/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.h index 2295cbb59f7..72e418dfab5 100644 --- a/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.h +++ b/TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.h @@ -5,7 +5,7 @@ // ============================================================================ // // = LIBRARY -// ECE255 +// SMI_ITERATOR // // = FILENAME // Content_Iterator_i.h @@ -29,30 +29,39 @@ # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ -// Implement the Web_Server::Content_Iterator interface. class Content_Iterator_i : public virtual POA_Web_Server::Content_Iterator, public virtual PortableServer::RefCountServantBase { + // = TITLE + // Implement the Web_Server::Content_Iterator interface. + // + // = DESCRIPTION + // This class implements the Iterator pattern to minimize memory + // requirements when retrieving data from a content server. + // Rather than retrieving one large chunk of data, this class + // iterates on the server so that smaller chunks of data are + // retrieved. + friend class Iterator_Factory_i; public: - // Constructor Content_Iterator_i (const char *filename, CORBA::ULong file_size); + // Constructor - // Destructor ~Content_Iterator_i (void); + // Destructor - // This operation returns the next <chunk> of the file starting at - // <offset>. If there are no more bindings, false is returned. virtual CORBA::Boolean next_chunk (CORBA::ULong offset, Web_Server::Chunk_Type_out chunk, CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException)); + // This operation returns the next <chunk> of the file starting at + // <offset>. If there are no more bindings, false is returned. - // Destroy the iterator. virtual void destroy (CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException)); + // Destroy the iterator. private: @@ -75,7 +84,4 @@ private: // for debugging purposes.) }; - - - #endif /* CONTENT_ITERATOR_I_H */ diff --git a/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.cpp b/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.cpp index 3adf63f4e66..ad0e0cad479 100644 --- a/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.cpp +++ b/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.cpp @@ -6,7 +6,7 @@ #include "Content_Iterator_i.h" #include "Iterator_Factory_i.h" -ACE_RCSID(SMI_Iterator, Iterator_Factory_i, "$Id$") +ACE_RCSID (SMI_Iterator, Iterator_Factory_i, "$Id$") void Iterator_Factory_i::get_iterator (const char *pathname, @@ -15,8 +15,6 @@ Iterator_Factory_i::get_iterator (const char *pathname, CORBA::Environment &ACE_TRY_ENV) ACE_THROW_SPEC ((CORBA::SystemException, Web_Server::Error_Result)) { - // Based on code available in H&V. - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Received request for file: <%s>\n"), pathname)); @@ -55,7 +53,13 @@ Iterator_Factory_i::get_iterator (const char *pathname, iterator_servant->_this (ACE_TRY_ENV); ACE_CHECK; - metadata = new Web_Server::Metadata_Type; + Web_Server::Metadata_Type *tmp = 0; + ACE_NEW_THROW_EX (tmp, + Web_Server::Metadata_Type, + CORBA::NO_MEMORY ()); + ACE_CHECK; + + metadata = tmp; if (this->modification_date (&file_status, metadata) != 0) diff --git a/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.h b/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.h index c78465eabd3..beb2f5c1866 100644 --- a/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.h +++ b/TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.h @@ -5,7 +5,7 @@ // ============================================================================ // // = LIBRARY -// ECE255 +// SMI_ITERATOR // // = FILENAME // Iterator_Factory_i.h @@ -32,29 +32,38 @@ struct stat; class Content_Iterator_i; -// Implement the Web_Server::Iterator_Factory interface. class Iterator_Factory_i : virtual public POA_Web_Server::Iterator_Factory { + // = TITLE + // Factory that creates a Content_Iterator that retrieves fixed + // size chunks of data from Content server. + // + // = DESCRIPTION + // This class creates a Content_Iterator that is set up to + // iteratively download a specific file. This same factory can + // be used to create Content_Iterators for other files. + public: - // This factory method returns a <Content_Iterator> that can be used - // to read the <contents> associated with <pathname> one ``chunk'' - // at a time. The <metadata> reports information about the - // <contents>. virtual void get_iterator (const char *pathname, Web_Server::Content_Iterator_out contents, Web_Server::Metadata_Type_out metadata, - CORBA::Environment &ACE_TRY_ENV) + CORBA::Environment &ACE_TRY_ENV = + TAO_default_environment ()) ACE_THROW_SPEC ((CORBA::SystemException, Web_Server::Error_Result)); + // This factory method returns a <Content_Iterator> that can be used + // to read the <contents> associated with <pathname> one ``chunk'' + // at a time. The <metadata> reports information about the + // <contents>. - // Set the file modification date in the metadata structure. int modification_date (struct stat *file_status, Web_Server::Metadata_Type_out metadata); + // Set the file modification date in the metadata structure. - // Set the type of file content in the metadata structure. int content_type (const char *filename, Web_Server::Metadata_Type_out metadata); + // Set the type of file content in the metadata structure. }; diff --git a/TAO/examples/Content_Server/SMI_Iterator/Web_Server.idl b/TAO/examples/Content_Server/SMI_Iterator/Web_Server.idl index 055f8159476..47838ae6d3b 100644 --- a/TAO/examples/Content_Server/SMI_Iterator/Web_Server.idl +++ b/TAO/examples/Content_Server/SMI_Iterator/Web_Server.idl @@ -7,14 +7,14 @@ module Web_Server interface Content_Iterator { + boolean next_chunk (in unsigned long offset, + out Chunk_Type chunk); // This operation returns the next <chunk> of the // file starting at <offset>. If there are // no more bindings, false is returned. - boolean next_chunk (in unsigned long offset, - out Chunk_Type chunk); - // This operation destroys the iterator. void destroy (); + // This operation destroys the iterator. }; exception Error_Result { @@ -27,22 +27,22 @@ module Web_Server struct Metadata_Type { - // Modification date. string modification_date; - - // Type of content. + // Modification date. + string content_type; + // Type of content. }; interface Iterator_Factory { - // This factory method returns a <Content_Iterator> that - // can be used to read the <contents> associated with - // <pathname> one ``chunk'' at a time. The <metadata> - // reports information about the <contents>. void get_iterator (in string pathname, out Content_Iterator contents, out Metadata_Type metadata) raises (Error_Result); + // This factory method returns a <Content_Iterator> that + // can be used to read the <contents> associated with + // <pathname> one ``chunk'' at a time. The <metadata> + // reports information about the <contents>. }; }; diff --git a/TAO/examples/Content_Server/SMI_Iterator/client.cpp b/TAO/examples/Content_Server/SMI_Iterator/client.cpp index 19c9343132a..bad90986181 100644 --- a/TAO/examples/Content_Server/SMI_Iterator/client.cpp +++ b/TAO/examples/Content_Server/SMI_Iterator/client.cpp @@ -34,7 +34,7 @@ main (int argc, char *argv[]) { if (argc < 2) ACE_ERROR_RETURN ((LM_ERROR, - "Usage: client filename\n"), + ACE_TEXT ("Usage: client filename\n")), -1); // Initialize the ORB. @@ -51,8 +51,8 @@ main (int argc, char *argv[]) ACE_TRY_CHECK; // Narrow to a Naming Context - CosNaming::NamingContext_var nc; - nc = CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); + CosNaming::NamingContext_var nc = + CosNaming::NamingContext::_narrow (obj.in (), ACE_TRY_ENV); ACE_TRY_CHECK; if (CORBA::is_nil (obj.in ())) |