ClientRequestInfo.cpp

Go to the documentation of this file.
00001 // $Id: ClientRequestInfo.cpp 77779 2007-03-23 11:48:02Z johnnyw $
00002 
00003 #include "tao/PI/ClientRequestInfo.h"
00004 
00005 #if TAO_HAS_INTERCEPTORS == 1
00006 
00007 ACE_RCSID (PI,
00008            ClientRequestInfo,
00009            "$Id: ClientRequestInfo.cpp 77779 2007-03-23 11:48:02Z johnnyw $")
00010 
00011 #include "tao/AnyTypeCode/Any.h"
00012 #include "tao/AnyTypeCode/ExceptionA.h"
00013 
00014 #include "tao/PI/PICurrent.h"
00015 #include "tao/PI/RequestInfo_Util.h"
00016 
00017 #include "tao/PolicyC.h"
00018 #include "tao/PortableInterceptorC.h"
00019 #include "tao/Invocation_Base.h"
00020 #include "tao/operation_details.h"
00021 #include "tao/Stub.h"
00022 #include "tao/ORB_Core.h"
00023 #include "tao/Profile.h"
00024 #include "tao/debug.h"
00025 #include "tao/Service_Context.h"
00026 #include "tao/Exception_Data.h"
00027 
00028 #include "ace/CORBA_macros.h"
00029 
00030 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00031 
00032 TAO_ClientRequestInfo::TAO_ClientRequestInfo (TAO::Invocation_Base *inv)
00033   : invocation_ (inv),
00034     rs_pi_current_ ()
00035 {
00036   this->setup_picurrent ();
00037 }
00038 
00039 void
00040 TAO_ClientRequestInfo::setup_picurrent (void)
00041 {
00042   // Retrieve the thread scope current (no TSS access incurred yet).
00043   CORBA::Object_ptr pi_current_obj =
00044     this->invocation_->orb_core ()->pi_current ();
00045 
00046   TAO::PICurrent *pi_current =
00047     dynamic_cast <TAO::PICurrent*> (pi_current_obj);
00048 
00049   // If the slot count is zero, then there is nothing to copy.
00050   // Prevent any copying (and hence TSS accesses) from occurring.
00051   if (pi_current != 0 && pi_current->slot_count () != 0)
00052     {
00053       // Retrieve the thread scope current.
00054       TAO::PICurrent_Impl *tsc = pi_current->tsc ();
00055 
00056       if (tsc != 0)
00057         {
00058           // Logically copy the TSC's slot table to the RSC.
00059           this->rs_pi_current_.take_lazy_copy (tsc);
00060        }
00061     }
00062 }
00063 
00064 IOP::ServiceContext *
00065 TAO_ClientRequestInfo::get_service_context_i (
00066     TAO_Service_Context &service_context_list,
00067     IOP::ServiceId id)
00068 {
00069   IOP::ServiceContext_var service_context;
00070 
00071   if (service_context_list.get_context (id, service_context.out ()) != 0)
00072     {
00073       // Found.
00074       return service_context._retn ();
00075     }
00076   else
00077     {
00078       // Not found.
00079       throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 26, CORBA::COMPLETED_NO);
00080     }
00081 }
00082 
00083 CORBA::Object_ptr
00084 TAO_ClientRequestInfo::target (void)
00085 {
00086   this->check_validity ();
00087 
00088   return CORBA::Object::_duplicate (this->invocation_->target ());
00089 }
00090 
00091 CORBA::Object_ptr
00092 TAO_ClientRequestInfo::effective_target (void)
00093 {
00094   this->check_validity ();
00095 
00096   return CORBA::Object::_duplicate (this->invocation_->effective_target ());
00097 }
00098 
00099 IOP::TaggedProfile *
00100 TAO_ClientRequestInfo::effective_profile (void)
00101 {
00102   this->check_validity ();
00103 
00104   IOP::TaggedProfile *tagged_profile = 0;
00105   ACE_NEW_THROW_EX (tagged_profile,
00106                     IOP::TaggedProfile,
00107                     CORBA::NO_MEMORY (
00108                       CORBA::SystemException::_tao_minor_code (
00109                         TAO::VMCID,
00110                         ENOMEM),
00111                       CORBA::COMPLETED_NO));
00112 
00113   IOP::TaggedProfile_var safe_tagged_profile = tagged_profile;
00114 
00115   TAO_Stub *stub =
00116     this->invocation_->effective_target ()->_stubobj ();
00117 
00118   IOP::TaggedProfile *ep =
00119     stub->profile_in_use ()->create_tagged_profile ();
00120 
00121   if (ep == 0)
00122     {
00123       throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 28, CORBA::COMPLETED_NO);
00124     }
00125 
00126   // @@BAD_PARAM exception
00127   tagged_profile->tag = ep->tag;
00128   tagged_profile->profile_data = ep->profile_data;  // Deep copy
00129 
00130   return safe_tagged_profile._retn ();
00131 }
00132 
00133 // Use at own risk. There is no way currently of extracting an
00134 // exception from an Any. This method is in place just to be compliant
00135 // with the spec.
00136 CORBA::Any *
00137 TAO_ClientRequestInfo::received_exception (void)
00138 {
00139   this->check_validity ();
00140 
00141   if (this->invocation_->reply_status () != PortableInterceptor::SYSTEM_EXCEPTION
00142       && this->invocation_->reply_status () != PortableInterceptor::USER_EXCEPTION)
00143     {
00144       throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00145     }
00146 
00147   // The spec says that if it is a user exception which can't be
00148   // inserted then the UNKNOWN exception needs to be thrown with minor
00149   // code 1.
00150 
00151   CORBA::Any * temp = 0;
00152 
00153   ACE_NEW_THROW_EX (temp,
00154                     CORBA::Any,
00155                     CORBA::NO_MEMORY (
00156                       CORBA::SystemException::_tao_minor_code (
00157                         TAO::VMCID,
00158                         ENOMEM),
00159                       CORBA::COMPLETED_NO));
00160 
00161   CORBA::Any_var caught_exception_var = temp;
00162 
00163   CORBA::Exception *caught_exception =
00164     invocation_->caught_exception ();
00165 
00166   if (caught_exception != 0)
00167     *temp <<= *(caught_exception);
00168 
00169   return caught_exception_var._retn ();
00170 }
00171 
00172 char *
00173 TAO_ClientRequestInfo::received_exception_id (void)
00174 {
00175   this->check_validity ();
00176 
00177   CORBA::Exception *caught_exception = invocation_->caught_exception ();
00178 
00179   if (caught_exception == 0)
00180     {
00181       throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00182     }
00183 
00184   return CORBA::string_dup (caught_exception->_rep_id ());
00185 }
00186 
00187 IOP::TaggedComponent *
00188 TAO_ClientRequestInfo::get_effective_component (IOP::ComponentId id)
00189 {
00190   this->check_validity ();
00191 
00192   TAO_Stub *stub = this->invocation_->effective_target ()->_stubobj ();
00193 
00194   TAO_Tagged_Components &ecs = stub->profile_in_use ()->tagged_components ();
00195 
00196   IOP::MultipleComponentProfile &components = ecs.components ();
00197 
00198   CORBA::ULong const len = components.length ();
00199   for (CORBA::ULong i = 0; i < len; ++i)
00200     {
00201       if (components[i].tag == id)
00202         {
00203           IOP::TaggedComponent *tagged_component = 0;
00204 
00205           // Only allocate a sequence if we have a tagged component
00206           // that matches the given IOP::ComponentId.
00207           ACE_NEW_THROW_EX (tagged_component,
00208                             IOP::TaggedComponent,
00209                             CORBA::NO_MEMORY (
00210                               CORBA::SystemException::_tao_minor_code (
00211                                 TAO::VMCID,
00212                                 ENOMEM),
00213                               CORBA::COMPLETED_NO));
00214 
00215           IOP::TaggedComponent_var safe_tagged_component =
00216             tagged_component;
00217 
00218           (*tagged_component) = components[i];  // Deep copy
00219 
00220           return safe_tagged_component._retn ();
00221         }
00222     }
00223 
00224   // No tagged component was found that matched the given
00225   // IOP::ComponentId.
00226   throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 28, CORBA::COMPLETED_NO);
00227 }
00228 
00229 IOP::TaggedComponentSeq *
00230 TAO_ClientRequestInfo::get_effective_components (IOP::ComponentId id)
00231 {
00232   this->check_validity ();
00233 
00234   TAO_Stub *stub = this->invocation_->target ()->_stubobj ();
00235 
00236   TAO_Tagged_Components &ecs = stub->profile_in_use ()->tagged_components ();
00237 
00238   IOP::MultipleComponentProfile &components = ecs.components ();
00239 
00240   IOP::TaggedComponentSeq *tagged_components = 0;
00241   IOP::TaggedComponentSeq_var safe_tagged_components;
00242 
00243   const CORBA::ULong len = components.length ();
00244   for (CORBA::ULong i = 0; i < len; ++i)
00245     {
00246       if (components[i].tag == id)
00247         {
00248           if (tagged_components == 0)
00249             {
00250               // Only allocate a sequence if we have tagged components
00251               // to place into the sequence.
00252               ACE_NEW_THROW_EX (tagged_components,
00253                                 IOP::TaggedComponentSeq,
00254                                 CORBA::NO_MEMORY (
00255                                   CORBA::SystemException::_tao_minor_code (
00256                                     TAO::VMCID,
00257                                     ENOMEM),
00258                                   CORBA::COMPLETED_NO));
00259 
00260               safe_tagged_components = tagged_components;
00261             }
00262 
00263           const CORBA::ULong old_len = safe_tagged_components->length ();
00264           safe_tagged_components->length (old_len + 1);
00265 
00266           safe_tagged_components[old_len] = components[i];  // Deep copy
00267         }
00268     }
00269 
00270   if (tagged_components == 0)
00271     {
00272       // No tagged component sequence was allocated, meaning no tagged
00273       // components were found that matched the given
00274       // IOP::ComponentId.
00275       throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 28, CORBA::COMPLETED_NO);
00276     }
00277 
00278   return safe_tagged_components._retn ();
00279 }
00280 
00281 CORBA::Policy_ptr
00282 TAO_ClientRequestInfo::get_request_policy (CORBA::PolicyType type)
00283 {
00284   this->check_validity ();
00285 
00286   // @@ Do we need to look anywhere else for the request policies?
00287 
00288 #if TAO_HAS_CORBA_MESSAGING == 1
00289   return this->invocation_->target ()->_get_policy (type);
00290 #else
00291   ACE_UNUSED_ARG (type);
00292 
00293   throw ::CORBA::NO_IMPLEMENT (
00294     CORBA::SystemException::_tao_minor_code (
00295       TAO::VMCID,
00296       ENOTSUP),
00297     CORBA::COMPLETED_NO);
00298 #endif  /* TAO_HAS_CORBA_MESSAGING == 1 */
00299 }
00300 
00301 void
00302 TAO_ClientRequestInfo::add_request_service_context (
00303     const IOP::ServiceContext & service_context,
00304     CORBA::Boolean replace)
00305 {
00306   this->check_validity ();
00307 
00308   // Get the service context from the list
00309   TAO_Service_Context &service_context_list =
00310     this->invocation_->request_service_context ();
00311 
00312   if (service_context_list.set_context (service_context, replace) == 0)
00313     {
00314       throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 15, CORBA::COMPLETED_NO);
00315     }
00316 }
00317 
00318 CORBA::ULong
00319 TAO_ClientRequestInfo::request_id (void)
00320 {
00321   this->check_validity ();
00322 
00323   // @todo We may have to worry about AMI once we support interceptors
00324   //       in AMI requests since the Invocation object no longer
00325   //       exists once an AMI request has been made.  In that case,
00326   //       the reply dispatcher address should be used.
00327 
00328   // The request ID must be unique across all outstanding requests.
00329   // To avoid synchronization overhead, the address of this Invocation
00330   // object is used as the request ID.  This guarantees that the
00331   // request ID is unique without being forced to acquire a lock.
00332   //
00333   // For 64-bit platforms, we right shift 8 bits and then use the
00334   // lower 32 bits of that shifted value.  Rather than losing the
00335   // upper 32 bits of significant digits by taking the lower 32 bits,
00336   // we only lose the upper 24 by doing the shift.  Basically, the
00337   // resulting request ID will comprised of bits 8 through 39.  This is
00338   // made possible by the fact that this Invocation object is large
00339   // enough to increase the likelihood that those bits (0 through 39)
00340   // are unique.  In particular, this->buffer_ is 512 bytes
00341   // (ACE_CDR::DEFAULT_BUFSIZE) long by default; implying that
00342   // dropping the lower 8 bits of the this Invocation object's 64 bit
00343   // address (i.e. 256 bytes) is not a problem.
00344 
00345   CORBA::ULong id = 0;
00346 
00347   // Note that we reinterpret_cast to an "unsigned long" instead of
00348   // CORBA::ULong since we need to first cast to an integer large
00349   // enough to hold an address to avoid compile-time warnings on some
00350   // 64-bit platforms.
00351 
00352   // 32 bit address
00353   if (sizeof (this) == 4)
00354     id =
00355       static_cast<CORBA::ULong> (
00356         reinterpret_cast<ptrdiff_t> (this->invocation_));
00357 
00358   // 64 bit address -- bits 8 through 39  (see notes above!)
00359   // In this case, we make sure this object is large enough to safely
00360   // do the right shift.  This is necessary since the size of the
00361   // buffer that makes this object is configurable.
00362   else if (sizeof (this) == 8
00363            && sizeof (*(this->invocation_)) > 256 /* 2 << 8 */)
00364     id =
00365       (static_cast<CORBA::ULong> (
00366          reinterpret_cast<ptrdiff_t> (this->invocation_)) >> 8) & 0xFFFFFFFFu;
00367 
00368   // 64 bit address -- lower 32 bits
00369   else if (sizeof (this) == 8)
00370     id =
00371       static_cast<CORBA::ULong> (
00372         reinterpret_cast<ptrdiff_t> (this->invocation_)) & 0xFFFFFFFFu;
00373 
00374   // @@ The following request ID generator prevents the
00375   //    PortableInterceptor::ClientRequestInterceptor::send_request()
00376   //    interception point from occuring before the call to connect,
00377   //    thus preventing us from adding an optimization that itself
00378   //    prevents a connection from being unnecessarily performed.
00379   //    Thus, the ClientRequestInfo object is forced to have its own
00380   //    request ID generator in order to make it possible to implement
00381   //    the above optimization.
00382   //
00383   //    Ideally, this request ID generator should go away, especially
00384   //    since it adds a lock to the critical path.
00385   //   else    // Fallback
00386   //     id = this->invocation_->request_id ();
00387 
00388   else
00389     {
00390       if (TAO_debug_level > 0)
00391         ACE_ERROR ((LM_ERROR,
00392                     "(%P|%t) ClientRequestInfo::request_id() failed\n"
00393                     "(%P|%t) since its request ID generator is not\n"
00394                     "(%P|%t) supported on this platform.\n"));
00395 
00396       throw ::CORBA::INTERNAL ();
00397     }
00398 
00399   return id;
00400 }
00401 
00402 char *
00403 TAO_ClientRequestInfo::operation (void)
00404 {
00405   this->check_validity ();
00406 
00407   return CORBA::string_dup (this->invocation_->operation_details ().opname  ());
00408 }
00409 
00410 Dynamic::ParameterList *
00411 TAO_ClientRequestInfo::arguments (void)
00412 {
00413   this->check_validity ();
00414 
00415   // Generate the argument list on demand.
00416   Dynamic::ParameterList *parameter_list =
00417     TAO_RequestInfo_Util::make_parameter_list ();
00418 
00419   Dynamic::ParameterList_var safe_parameter_list = parameter_list;
00420 
00421   if (this->parameter_list (*parameter_list) == false)
00422     throw ::CORBA::MARSHAL ();
00423 
00424   return safe_parameter_list._retn ();
00425 }
00426 
00427 bool
00428 TAO_ClientRequestInfo::parameter_list (Dynamic::ParameterList &param_list)
00429 {
00430   // Account for the return type that is in the argument list.
00431   param_list.length (this->invocation_->operation_details ().args_num () - 1);
00432 
00433   for (CORBA::ULong i = 1; i != this->invocation_->operation_details ().args_num (); ++i)
00434     {
00435       TAO::Argument *argument =
00436         this->invocation_->operation_details ().args ()[i];
00437       Dynamic::Parameter &p = param_list[i - 1];
00438       p.mode = argument->mode ();
00439       // When we are in send_request and have an out argument, then
00440       // don't copy it, just let the any be empty with typecode tk_null
00441       if ((this->invocation_->invoke_status () != TAO::TAO_INVOKE_START) ||
00442           (this->invocation_->invoke_status () == TAO::TAO_INVOKE_START &&
00443            argument->mode () != CORBA::PARAM_OUT))
00444         {
00445           argument->interceptor_value (&p.argument);
00446         }
00447     }
00448 
00449   return true;
00450 }
00451 
00452 Dynamic::ExceptionList *
00453 TAO_ClientRequestInfo::exceptions (void)
00454 {
00455   this->check_validity ();
00456 
00457   Dynamic::ExceptionList *exception_list =
00458     TAO_RequestInfo_Util::make_exception_list ();
00459 
00460   Dynamic::ExceptionList_var safe_exception_list = exception_list;
00461 
00462   if (this->exception_list (*exception_list) == false)
00463     throw ::CORBA::MARSHAL ();
00464 
00465   return safe_exception_list._retn ();
00466 }
00467 
00468 bool
00469 TAO_ClientRequestInfo::exception_list (Dynamic::ExceptionList &exception_list)
00470 {
00471   if (this->invocation_->operation_details ().ex_count ())
00472     {
00473       exception_list.length (this->invocation_->operation_details ().ex_count ());
00474 
00475       for (CORBA::ULong i = 0;
00476            i != this->invocation_->operation_details ().ex_count ();
00477            ++i)
00478         {
00479           CORBA::TypeCode_ptr tcp =
00480             this->invocation_->operation_details ().ex_data ()[i].tc_ptr;
00481           if (!CORBA::is_nil (tcp))
00482             {
00483               exception_list[i] = tcp;
00484             }
00485         }
00486     }
00487   return true;
00488 }
00489 
00490 Dynamic::ContextList *
00491 TAO_ClientRequestInfo::contexts (void)
00492 {
00493   this->check_validity ();
00494 
00495   throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00496 }
00497 
00498 Dynamic::RequestContext *
00499 TAO_ClientRequestInfo::operation_context (void)
00500 {
00501   this->check_validity ();
00502 
00503   throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00504 }
00505 
00506 CORBA::Any *
00507 TAO_ClientRequestInfo::result (void)
00508 {
00509   this->check_validity ();
00510 
00511   // Generate the result on demand.
00512   static const CORBA::Boolean tk_void_any = 0;
00513   CORBA::Any *result_any =
00514     TAO_RequestInfo_Util::make_any (tk_void_any);
00515 
00516   CORBA::Any_var safe_result_any = result_any;
00517 
00518   if (this->result (result_any) == false)
00519     throw ::CORBA::MARSHAL ();
00520 
00521   return safe_result_any._retn ();
00522 }
00523 
00524 bool
00525 TAO_ClientRequestInfo::result (CORBA::Any *any)
00526 {
00527   // Result is always first element in TAO::Argument array.
00528   TAO::Argument * const r = this->invocation_->operation_details ().args ()[0];
00529 
00530   r->interceptor_value (any);
00531 
00532   return true;
00533 }
00534 
00535 CORBA::Boolean
00536 TAO_ClientRequestInfo::response_expected (void)
00537 {
00538   this->check_validity ();
00539 
00540   return this->invocation_->response_expected ();
00541 }
00542 
00543 Messaging::SyncScope
00544 TAO_ClientRequestInfo::sync_scope (void)
00545 {
00546   this->check_validity ();
00547 
00548   return this->invocation_->operation_details ().response_flags ();
00549 }
00550 
00551 PortableInterceptor::ReplyStatus
00552 TAO_ClientRequestInfo::reply_status (void)
00553 {
00554   this->check_validity ();
00555 
00556   PortableInterceptor::ReplyStatus const status =
00557     this->invocation_->reply_status();
00558   if (status == -1 || status == PortableInterceptor::UNKNOWN)
00559     {
00560       // A reply hasn't been received yet.
00561       throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00562     }
00563 
00564   return status;
00565 }
00566 
00567 CORBA::Object_ptr
00568 TAO_ClientRequestInfo::forward_reference (void)
00569 {
00570   this->check_validity ();
00571 
00572   if (this->invocation_->reply_status() != PortableInterceptor::LOCATION_FORWARD)
00573     {
00574       throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00575     }
00576 
00577   // TAO::Invocation_Base::forward_reference() already duplicates the
00578   // reference before returning it so there is no need to duplicate it
00579   // here.
00580   return this->invocation_->forwarded_reference ();
00581 }
00582 
00583 CORBA::Any *
00584 TAO_ClientRequestInfo::get_slot (PortableInterceptor::SlotId id)
00585 {
00586   this->check_validity ();
00587 
00588   return this->rs_pi_current_.get_slot (id);
00589 }
00590 
00591 IOP::ServiceContext *
00592 TAO_ClientRequestInfo::get_request_service_context (IOP::ServiceId id)
00593 {
00594   this->check_validity ();
00595 
00596   // Get the service context from the list
00597   TAO_Service_Context &service_context_list =
00598     this->invocation_->request_service_context ();
00599 
00600   return this->get_service_context_i (service_context_list, id);
00601 }
00602 
00603 IOP::ServiceContext *
00604 TAO_ClientRequestInfo::get_reply_service_context (IOP::ServiceId id)
00605 {
00606   this->check_validity ();
00607 
00608   // Get the service context from the list
00609   TAO_Service_Context &service_context_list =
00610     this->invocation_->reply_service_context ();
00611 
00612   return this->get_service_context_i (service_context_list, id);
00613 }
00614 
00615 void
00616 TAO_ClientRequestInfo::check_validity (void)
00617 {
00618   if (this->invocation_ == 0)
00619     throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
00620 }
00621 
00622 void
00623 TAO_ClientRequestInfo::tao_ft_expiration_time (TimeBase::TimeT time)
00624 {
00625   this->invocation_->operation_details ().ft_expiration_time (time);
00626 }
00627 
00628 TimeBase::TimeT
00629 TAO_ClientRequestInfo::tao_ft_expiration_time (void) const
00630 {
00631   return this->invocation_->operation_details ().ft_expiration_time ();
00632 }
00633 
00634 void
00635 TAO_ClientRequestInfo::tao_ft_retention_id (CORBA::Long request_id)
00636 {
00637   this->invocation_->operation_details ().ft_retention_id (request_id) ;
00638 }
00639 
00640 CORBA::Long
00641 TAO_ClientRequestInfo::tao_ft_retention_id (void) const
00642 {
00643   return this->invocation_->operation_details ().ft_retention_id ();
00644 }
00645 
00646 TAO_END_VERSIONED_NAMESPACE_DECL
00647 
00648 #endif /* TAO_HAS_INTERCEPTORS == 1 */

Generated on Sun Jan 27 13:29:59 2008 for TAO_PI by doxygen 1.3.6