summaryrefslogtreecommitdiff
path: root/TAO/examples/Content_Server
diff options
context:
space:
mode:
authorOssama Othman <ossama-othman@users.noreply.github.com>2000-06-21 22:54:25 +0000
committerOssama Othman <ossama-othman@users.noreply.github.com>2000-06-21 22:54:25 +0000
commitc489facc3cbe2292a7edc78920d6d316b9250a65 (patch)
tree8d91b9d20428fdeda025b5d46255de4b8cc440cb /TAO/examples/Content_Server
parentfaa66c456d64718a1a4080f40126842b16da1f59 (diff)
downloadATCD-c489facc3cbe2292a7edc78920d6d316b9250a65.tar.gz
ChangeLogTag:Wed Jun 21 15:51:10 2000 Ossama Othman <ossama@uci.edu>
Diffstat (limited to 'TAO/examples/Content_Server')
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.cpp2
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/Content_Iterator_i.h24
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.cpp20
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/Iterator_Factory_i.h23
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/Iterator_Handler.h24
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/client.cpp8
-rw-r--r--TAO/examples/Content_Server/AMI_Iterator/server.cpp4
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Callback.cpp296
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Callback.h108
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Callback_Handler.cpp17
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Callback_Handler.h43
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Callback_i.cpp12
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Callback_i.h31
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Makefile13
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.cpp34
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Factory_i.h19
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.cpp6
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/Push_Iterator_Handler.h29
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/README70
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/client.cpp153
-rw-r--r--TAO/examples/Content_Server/AMI_Observer/server.cpp10
-rw-r--r--TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.cpp10
-rw-r--r--TAO/examples/Content_Server/SMI_Iterator/Content_Iterator_i.h26
-rw-r--r--TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.cpp12
-rw-r--r--TAO/examples/Content_Server/SMI_Iterator/Iterator_Factory_i.h27
-rw-r--r--TAO/examples/Content_Server/SMI_Iterator/Web_Server.idl20
-rw-r--r--TAO/examples/Content_Server/SMI_Iterator/client.cpp6
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 ()))