summaryrefslogtreecommitdiff
path: root/TAO/tao/Messaging
diff options
context:
space:
mode:
authorJohnny Willemsen <jwillemsen@remedy.nl>2004-08-30 07:08:00 +0000
committerJohnny Willemsen <jwillemsen@remedy.nl>2004-08-30 07:08:00 +0000
commit5a6e4e4e379fee8c6caef815f88e2d8e49e1c19e (patch)
treec4289712cc73238a1d243e076a146c59117ed13a /TAO/tao/Messaging
parentded1a1e50201be2d3d1dfec3430f7f8c37db73cf (diff)
downloadATCD-5a6e4e4e379fee8c6caef815f88e2d8e49e1c19e.tar.gz
ChangeLogTag: Mon Aug 30 07:06:12 UTC 2004 Johnny Willemsen <jwillemsen@remedy.nl>
Diffstat (limited to 'TAO/tao/Messaging')
-rw-r--r--TAO/tao/Messaging/AMH_Response_Handler.cpp273
-rw-r--r--TAO/tao/Messaging/AMH_Response_Handler.h216
2 files changed, 489 insertions, 0 deletions
diff --git a/TAO/tao/Messaging/AMH_Response_Handler.cpp b/TAO/tao/Messaging/AMH_Response_Handler.cpp
new file mode 100644
index 00000000000..596191756d0
--- /dev/null
+++ b/TAO/tao/Messaging/AMH_Response_Handler.cpp
@@ -0,0 +1,273 @@
+// $Id$
+
+#include "tao/Messaging/AMH_Response_Handler.h"
+#include "tao/TAO_Server_Request.h"
+#include "tao/Transport.h"
+#include "tao/CDR.h"
+#include "tao/ORB_Core.h"
+#include "tao/ORB.h"
+#include "tao/Pluggable_Messaging.h"
+#include "tao/Pluggable_Messaging_Utils.h"
+#include "tao/GIOP_Utils.h"
+#include "tao/debug.h"
+#include "tao/Buffer_Allocator_T.h"
+#include "ace/Copy_Disabled.h"
+
+TAO_AMH_Response_Handler::TAO_AMH_Response_Handler ()
+ : mesg_base_ (0)
+ , request_id_ (0)
+ , transport_ (0)
+ , orb_core_ (0)
+ , argument_flag_ (1)
+ , exception_type_ (TAO_GIOP_NO_EXCEPTION)
+ , reply_status_ (TAO_RS_UNINITIALIZED)
+ , allocator_ (0)
+{
+}
+
+TAO_AMH_Response_Handler::~TAO_AMH_Response_Handler (void)
+{
+ this->transport_->remove_reference ();
+
+ // Since we are destroying the object we put a huge lock around the
+ // whole destruction process (just paranoid).
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+
+ if (this->response_expected_ == 0) //oneway ?
+ {
+ return;
+ }
+
+ // If the ResponseHandler is being destroyed before a reply has
+ // been sent to the client, we send a system exception
+ // CORBA::NO_RESPONSE, with minor code to indicate the problem.
+ if (this->reply_status_ == TAO_RS_SENT)
+ {
+ return;
+ }
+
+ // If sending the exception to the client fails, then we just give
+ // up, release the transport and return.
+ ACE_DECLARE_NEW_CORBA_ENV;
+ ACE_TRY
+ {
+ CORBA::NO_RESPONSE ex (CORBA::SystemException::_tao_minor_code
+ (TAO_AMH_REPLY_LOCATION_CODE,
+ EFAULT),
+ CORBA::COMPLETED_NO);
+ this->_tao_rh_send_exception (ex ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ ACE_CATCHALL
+ {
+ }
+ ACE_ENDTRY;
+ ACE_CHECK;
+ }
+}
+
+void
+TAO_AMH_Response_Handler::init(TAO_ServerRequest &server_request,
+ TAO_AMH_BUFFER_ALLOCATOR* allocator)
+{
+ mesg_base_ = server_request.mesg_base_;
+ request_id_ = server_request.request_id_;
+ response_expected_ = server_request.response_expected_;
+ transport_ = server_request.transport ();
+ orb_core_ = server_request.orb_core ();
+ allocator_ = allocator;
+
+ this->transport_->add_reference ();
+}
+
+void
+TAO_AMH_Response_Handler::_tao_rh_init_reply (ACE_ENV_SINGLE_ARG_DECL)
+{
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+ if (this->reply_status_ != TAO_RS_UNINITIALIZED)
+ {
+ // Looks like someone is trying to call an AMH method
+ // more than once
+ //
+ // We assume that the servant has already processed the
+ // request and is now trying to send back the reply. Hence we
+ // say that the operation has completed but let the server
+ // anyway that it is not doing something right.
+ ACE_THROW (CORBA::BAD_INV_ORDER
+ (CORBA::SystemException::_tao_minor_code
+ (TAO_AMH_REPLY_LOCATION_CODE,
+ EEXIST),
+ CORBA::COMPLETED_YES));
+ }
+ }
+
+ // Construct our reply generator.
+ TAO_Pluggable_Reply_Params_Base reply_params;
+ reply_params.request_id_ = this->request_id_;
+ reply_params.service_context_notowned (&(this->reply_service_context_.service_info ()));
+ reply_params.argument_flag_ = this->argument_flag_;
+
+ if (this->exception_type_ == TAO_GIOP_NO_EXCEPTION)
+ {
+ reply_params.reply_status_ = TAO_PLUGGABLE_MESSAGE_NO_EXCEPTION;
+ }
+ else
+ {
+ reply_params.reply_status_ = this->exception_type_;
+ }
+
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+
+ this->mesg_base_->generate_reply_header (this->_tao_out,
+ reply_params);
+
+ // We are done initialising the reply
+ this->reply_status_ = TAO_RS_INITIALIZED;
+ }
+
+}
+
+void
+TAO_AMH_Response_Handler::_tao_rh_send_reply (ACE_ENV_SINGLE_ARG_DECL)
+{
+
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+
+ // If the reply has not been initialised, raise an exception to the
+ // server-app saying it is not doing something right.
+ if (this->reply_status_ != TAO_RS_INITIALIZED)
+ {
+ ACE_THROW (CORBA::BAD_INV_ORDER (
+ CORBA::SystemException::_tao_minor_code (
+ TAO_AMH_REPLY_LOCATION_CODE,
+ ENOTSUP),
+ CORBA::COMPLETED_YES));
+ }
+ this->reply_status_ = TAO_RS_SENDING;
+ }
+
+ // Send the message.
+ int result = this->transport_->send_message (this->_tao_out,
+ 0,
+ TAO_Transport::TAO_REPLY);
+
+ if (result == -1)
+ {
+ if (TAO_debug_level > 0)
+ {
+ // No exception but some kind of error, yet a response
+ // is required.
+ ACE_ERROR ((
+ LM_ERROR,
+ ACE_TEXT ("TAO: (%P|%t) %p: cannot send NO_EXCEPTION reply\n"),
+ ACE_TEXT ("TAO_AMH_Response_Handler::_tao_rh_send_reply")
+ ));
+ }
+ }
+
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+ this->reply_status_ = TAO_RS_SENT;
+ }
+}
+
+void
+TAO_AMH_Response_Handler::_tao_rh_send_exception (CORBA::Exception &ex
+ ACE_ENV_ARG_DECL)
+{
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+ if (this->reply_status_ != TAO_RS_UNINITIALIZED)
+ {
+ ACE_THROW (CORBA::BAD_INV_ORDER (
+ CORBA::SystemException::_tao_minor_code (
+ TAO_AMH_REPLY_LOCATION_CODE,
+ ENOTSUP),
+ CORBA::COMPLETED_YES));
+ }
+ this->reply_status_ = TAO_RS_SENDING;
+ }
+
+ TAO_Pluggable_Reply_Params_Base reply_params;
+ reply_params.request_id_ = this->request_id_;
+ reply_params.svc_ctx_.length (0);
+ reply_params.service_context_notowned (&this->reply_service_context_.service_info ());
+ reply_params.argument_flag_ = 1;
+ reply_params.reply_status_ = TAO_GIOP_USER_EXCEPTION;
+ // @@ It appears as if there should be a more efficient way to do
+ // this: the caller already knows this because it is part of the
+ // ExceptionHolder information.
+ if (CORBA::SystemException::_downcast (&ex))
+ reply_params.reply_status_ = TAO_GIOP_SYSTEM_EXCEPTION;
+
+ if (this->mesg_base_->generate_exception_reply (this->_tao_out,
+ reply_params,
+ ex) == -1)
+ {
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ // Send the Exception
+ if (this->transport_->send_message (this->_tao_out,
+ 0,
+ TAO_Transport::TAO_REPLY) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TAO: (%P|%t|%N|%l): ")
+ ACE_TEXT ("TAO_AMH_Response_Handler: could not send exception reply\n")));
+ }
+
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mutex_);
+ this->reply_status_ = TAO_RS_SENT;
+ }
+}
+
+void
+TAO_AMH_Response_Handler::_remove_ref (void)
+{
+ {
+ ACE_GUARD (TAO_SYNCH_MUTEX,
+ mon,
+ this->refcount_lock_);
+
+ --this->refcount_;
+
+ if (this->refcount_ > 0)
+ return;
+ }
+
+ if (this->allocator_)
+ {
+ TAO::TAO_Buffer_Allocator<TAO_AMH_Response_Handler, TAO_AMH_BUFFER_ALLOCATOR> allocator (allocator_);
+
+ allocator.release(this);
+ }
+ else
+ {
+ delete this;
+ }
+
+ return;
+}
+
+namespace TAO
+{
+ void
+ ARH_Refcount_Functor::operator () (
+ TAO_AMH_Response_Handler *arh)
+ ACE_THROW_SPEC (())
+ {
+ (void) arh->_remove_ref ();
+ }
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/TAO/tao/Messaging/AMH_Response_Handler.h b/TAO/tao/Messaging/AMH_Response_Handler.h
new file mode 100644
index 00000000000..678aa406821
--- /dev/null
+++ b/TAO/tao/Messaging/AMH_Response_Handler.h
@@ -0,0 +1,216 @@
+// -*- C++ -*-
+
+// =========================================================================
+/**
+ * @file AMH_Response_Handler.h
+ *
+ * $Id$
+ *
+ * @author Mayur Deshpande <mayur@ics.uci.edu>
+ *
+ */
+// =========================================================================
+
+#ifndef TAO_AMH_RESPONSE_HANDLER_H
+#define TAO_AMH_RESPONSE_HANDLER_H
+
+#include "messaging_export.h"
+
+#include "tao/Allocator.h"
+#include "tao/Service_Context.h"
+#include "tao/CDR.h"
+#include "tao/LocalObject.h"
+#include "tao/Buffer_Allocator_T.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+#include "ace/Null_Mutex.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class TAO_Transport;
+class TAO_Pluggable_Messaging;
+class TAO_Output_CDR;
+class TAO_ORB_Core;
+class TAO_ServerRequest;
+class ACE_Allocator;
+
+typedef ACE_Allocator TAO_AMH_BUFFER_ALLOCATOR;
+
+/**
+ * @class TAO_AMH_Response_Handler
+ *
+ * @brief Class representing an Asynchronous-Method-Handling (AMH)
+ * ResponseHandler (RH) object.
+ *
+ * Class encapsulates state required to send a response back to the
+ * client independent of the thread that originally created the state
+ * on the activation-record. Thus the required state (copied from
+ * TAO_Server_Request) is 'stored' on the heap.
+ *
+ * One RH is created for every client request and the RH can be used
+ * only once i.e., the asynchronous method can be called only once.
+ * This class also encapsulates various initialisation and
+ * response-sending functionality that is common to all RHs (generated
+ * by the IDL compiler). Thus the IDL-compiler has to generate less
+ * code which in turn reduces the overall code size for an
+ * application.
+ */
+class TAO_Messaging_Export TAO_AMH_Response_Handler
+// @@ Mayur, this is not the correct way to use
+// TAO_LocalRefCounted_Object. Application code is supposed to use
+// it when necessary. You're forcing applications to use a
+// reference counted version of their AMH_Response_Handler. This
+// isn't consistent with the specified semantics detailed in the
+// CCM spec. Please remove this and place it where appropriate in
+// your AMH tests and examples.
+ : virtual public TAO_Local_RefCounted_Object
+{
+public:
+
+ /// Constructor
+ TAO_AMH_Response_Handler ();
+
+ /// Destructor
+ /**
+ * Releases the transport and in case of an error, sends the appropriate
+ * exception back to the client
+ */
+ virtual ~TAO_AMH_Response_Handler (void);
+
+ /**
+ * Stores necessary information from a TAO_Server_Request onto the heap
+ */
+ virtual void init(TAO_ServerRequest &server_request,
+ TAO_AMH_BUFFER_ALLOCATOR* allocator);
+
+ /// @name Mutators for refcount
+ //@{
+ virtual void _remove_ref (void);
+ //@}
+
+protected:
+
+ /// Sets up the various parameters in anticipation of returning a reply
+ /// to the client. return/OUT/INOUT arguments are marshalled into the
+ /// Output stream after this method has been called.
+ void _tao_rh_init_reply (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Sends the marshalled reply back to the client.
+ void _tao_rh_send_reply (ACE_ENV_SINGLE_ARG_DECL);
+
+ /// Send back an exception to the client.
+ void _tao_rh_send_exception (CORBA::Exception &ex
+ ACE_ENV_ARG_DECL);
+
+protected:
+
+ /// The outgoing CDR stream
+ /**
+ * The IDL-generated ResponseHandler implementations used this field
+ * to marshal the response.
+ * Making it a field instead of a public accessor makes the code in
+ * the generated ResponseHandler implementation a lot more readable.
+ */
+ TAO_OutputCDR _tao_out;
+
+private:
+
+ // Private and undefined, standard C++ idiom to prohibit copying.
+ ACE_UNIMPLEMENTED_FUNC (TAO_AMH_Response_Handler (const TAO_AMH_Response_Handler&))
+ ACE_UNIMPLEMENTED_FUNC (TAO_AMH_Response_Handler& operator= (const TAO_AMH_Response_Handler&))
+
+private:
+ /// Pointer to the original message-base
+ TAO_Pluggable_Messaging *mesg_base_;
+
+ /// Copy of the request-id of the original Server-Request
+ CORBA::ULong request_id_;
+
+ CORBA::Boolean response_expected_;
+
+ /// Handle to transport through which the reply will be sent
+ /// Copy of transport in original Server_Request
+ TAO_Transport *transport_;
+
+ /// A pointer to the ORB Core for the context where the request was
+ /// created.
+ TAO_ORB_Core *orb_core_;
+
+ /// The reply service context
+ TAO_Service_Context reply_service_context_;
+
+ /// Alwyas set to true (we always have something to return to the
+ /// client
+ // @@ Mayur: I think not! This is used to generate padding in GIOP
+ // 1.2 messages (where the payload must start on an 8-byte
+ // boundary. But some replys have no payload (only header), in
+ // those cases you cannot insert the padding. We need the
+ // ResponseHandler to set this field correctly!
+ CORBA::Boolean argument_flag_;
+
+ // TAO_GIOP_ReplyStatusType exception_type_;
+ /// Exception type (will be NO_EXCEPTION in the majority of the
+ /// cases).
+ // @@ Mayur: I do not think we need this one, we can deduce the type
+ // of reply depending on the _tao_rh_*() method called.
+ CORBA::ULong exception_type_;
+
+ /**
+ * Various states the ResponseHandler can be in.
+ *
+ * These states represent various states the RH can be in and
+ * the states are used not only in implementing the 'once-only semantics of
+ * RHs, but in making sure well the call thread-safe as well.
+ */
+ enum Reply_Status
+ {
+ TAO_RS_UNINITIALIZED,
+ TAO_RS_INITIALIZED,
+ TAO_RS_SENDING,
+ TAO_RS_SENT
+ };
+ Reply_Status reply_status_;
+ // I would use the "state pattern"..
+ // Carlos, Isn't that an overkill?
+ // @@ Mayur: it depends on what form of the "State Pattern" you
+ // use. The more generic form, as described in GoF, uses a class
+ // for each state, super-elegant but indeed a bit heavy handed.
+ // The lighter-weight form (using a state variable
+
+ /// Mutex to ensure the AMH-RH method call is thread-safe.
+ ACE_SYNCH_MUTEX mutex_;
+
+ /// Allocator used to allocate this object. If zero then we are allocated
+ /// from the heap
+ TAO_AMH_BUFFER_ALLOCATOR* allocator_;
+};
+
+namespace TAO
+{
+ /**
+ * @class ARH_Refcount_Functor
+ *
+ * @brief Functor for refcounting of TAO_AMH_Response_Handler
+ *
+ * This is used to safely handle the destruction of
+ * TAO_AMH_Response_Handler objects which are created on the
+ * heap. We cannot use auto_ptr <> since it calls delete on the
+ * pointer, and calling delete on TAO_AMH_Response_Handler *
+ * will not work. Hence this functor will be used with Auto_Functor
+ * class to handle the memory safely.
+ *
+ * @todo Ideally, this class can be a generic class. But that
+ * requires quite a bit of cleanup within TAO to be more useful.
+ */
+ class TAO_Messaging_Export ARH_Refcount_Functor
+ {
+ public:
+ void operator() (TAO_AMH_Response_Handler *arh)
+ ACE_THROW_SPEC (());
+ };
+
+}
+
+#endif /* TAO_AMH_RESPONSE_HANDLER_H */