Revert "Minor modernization of DynamicAny code"
[ACE_TAO.git] / TAO / tao / PI / ClientRequestInfo.cpp
blobd2b95eb562e9e369f6f3a4bc3f1afe21f309fbeb
1 #include "tao/PI/ClientRequestInfo.h"
3 #if TAO_HAS_INTERCEPTORS == 1
5 #include "tao/AnyTypeCode/Any.h"
6 #include "tao/AnyTypeCode/ExceptionA.h"
8 #include "tao/PI/PICurrent.h"
9 #include "tao/PI/RequestInfo_Util.h"
11 #include "tao/PolicyC.h"
12 #include "tao/PortableInterceptorC.h"
13 #include "tao/Invocation_Base.h"
14 #include "tao/operation_details.h"
15 #include "tao/Stub.h"
16 #include "tao/ORB_Core.h"
17 #include "tao/Profile.h"
18 #include "tao/debug.h"
19 #include "tao/Service_Context.h"
20 #include "tao/Exception_Data.h"
22 #include "ace/CORBA_macros.h"
24 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
26 TAO_ClientRequestInfo::TAO_ClientRequestInfo (TAO::Invocation_Base *inv)
27 : invocation_ (inv),
28 rs_pi_current_ ()
30 this->setup_picurrent ();
33 void
34 TAO_ClientRequestInfo::setup_picurrent ()
36 // Retrieve the thread scope current (no TSS access incurred yet).
37 CORBA::Object_ptr pi_current_obj =
38 this->invocation_->stub ()->orb_core ()->pi_current ();
40 TAO::PICurrent *pi_current =
41 dynamic_cast <TAO::PICurrent*> (pi_current_obj);
43 // If the slot count is zero, then there is nothing to copy.
44 // Prevent any copying (and hence TSS accesses) from occurring.
45 if (pi_current != 0 && pi_current->slot_count () != 0)
47 // Retrieve the thread scope current.
48 TAO::PICurrent_Impl *tsc = pi_current->tsc ();
50 if (tsc != 0)
52 // Logically copy the TSC's slot table to the RSC.
53 this->rs_pi_current_.take_lazy_copy (tsc);
58 IOP::ServiceContext *
59 TAO_ClientRequestInfo::get_service_context_i (
60 TAO_Service_Context &service_context_list,
61 IOP::ServiceId id)
63 IOP::ServiceContext_var service_context;
65 if (service_context_list.get_context (id, service_context.out ()) != 0)
67 // Found.
68 return service_context._retn ();
70 else
72 // Not found.
73 throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 26, CORBA::COMPLETED_NO);
77 CORBA::Object_ptr
78 TAO_ClientRequestInfo::target ()
80 this->check_validity ();
82 return CORBA::Object::_duplicate (this->invocation_->target ());
85 CORBA::Object_ptr
86 TAO_ClientRequestInfo::effective_target ()
88 this->check_validity ();
90 return CORBA::Object::_duplicate (this->invocation_->effective_target ());
93 IOP::TaggedProfile *
94 TAO_ClientRequestInfo::effective_profile ()
96 this->check_validity ();
98 IOP::TaggedProfile *tagged_profile = 0;
99 ACE_NEW_THROW_EX (tagged_profile,
100 IOP::TaggedProfile,
101 CORBA::NO_MEMORY (
102 CORBA::SystemException::_tao_minor_code (
103 TAO::VMCID,
104 ENOMEM),
105 CORBA::COMPLETED_NO));
107 IOP::TaggedProfile_var safe_tagged_profile = tagged_profile;
109 TAO_Stub *stub =
110 this->invocation_->effective_target ()->_stubobj ();
112 IOP::TaggedProfile *ep =
113 stub->profile_in_use ()->create_tagged_profile ();
115 if (ep == 0)
117 throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 28, CORBA::COMPLETED_NO);
120 // @@BAD_PARAM exception
121 tagged_profile->tag = ep->tag;
122 tagged_profile->profile_data = ep->profile_data; // Deep copy
124 return safe_tagged_profile._retn ();
127 // Use at own risk. There is no way currently of extracting an
128 // exception from an Any. This method is in place just to be compliant
129 // with the spec.
130 CORBA::Any *
131 TAO_ClientRequestInfo::received_exception ()
133 this->check_validity ();
135 if (this->invocation_->pi_reply_status () != PortableInterceptor::SYSTEM_EXCEPTION
136 && this->invocation_->pi_reply_status () != PortableInterceptor::USER_EXCEPTION)
138 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
141 // The spec says that if it is a user exception which can't be
142 // inserted then the UNKNOWN exception needs to be thrown with minor
143 // code 1.
144 CORBA::Any * temp = 0;
146 ACE_NEW_THROW_EX (temp,
147 CORBA::Any,
148 CORBA::NO_MEMORY (
149 CORBA::SystemException::_tao_minor_code (
150 TAO::VMCID,
151 ENOMEM),
152 CORBA::COMPLETED_NO));
154 CORBA::Any_var caught_exception_var = temp;
156 CORBA::Exception *caught_exception =
157 invocation_->caught_exception ();
159 if (caught_exception != 0)
160 *temp <<= *(caught_exception);
162 return caught_exception_var._retn ();
165 char *
166 TAO_ClientRequestInfo::received_exception_id ()
168 this->check_validity ();
170 CORBA::Exception *caught_exception = invocation_->caught_exception ();
172 if (caught_exception == 0)
174 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
177 return CORBA::string_dup (caught_exception->_rep_id ());
180 IOP::TaggedComponent *
181 TAO_ClientRequestInfo::get_effective_component (IOP::ComponentId id)
183 this->check_validity ();
185 TAO_Stub *stub = this->invocation_->effective_target ()->_stubobj ();
187 TAO_Tagged_Components &ecs = stub->profile_in_use ()->tagged_components ();
189 IOP::MultipleComponentProfile &components = ecs.components ();
191 CORBA::ULong const len = components.length ();
192 for (CORBA::ULong i = 0; i < len; ++i)
194 if (components[i].tag == id)
196 IOP::TaggedComponent *tagged_component = 0;
198 // Only allocate a sequence if we have a tagged component
199 // that matches the given IOP::ComponentId.
200 ACE_NEW_THROW_EX (tagged_component,
201 IOP::TaggedComponent,
202 CORBA::NO_MEMORY (
203 CORBA::SystemException::_tao_minor_code (
204 TAO::VMCID,
205 ENOMEM),
206 CORBA::COMPLETED_NO));
208 IOP::TaggedComponent_var safe_tagged_component =
209 tagged_component;
211 (*tagged_component) = components[i]; // Deep copy
213 return safe_tagged_component._retn ();
217 // No tagged component was found that matched the given
218 // IOP::ComponentId.
219 throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 28, CORBA::COMPLETED_NO);
222 IOP::TaggedComponentSeq *
223 TAO_ClientRequestInfo::get_effective_components (IOP::ComponentId id)
225 this->check_validity ();
227 TAO_Stub *stub = this->invocation_->target ()->_stubobj ();
229 TAO_Tagged_Components &ecs = stub->profile_in_use ()->tagged_components ();
231 IOP::MultipleComponentProfile &components = ecs.components ();
233 IOP::TaggedComponentSeq *tagged_components = 0;
234 IOP::TaggedComponentSeq_var safe_tagged_components;
236 const CORBA::ULong len = components.length ();
237 for (CORBA::ULong i = 0; i < len; ++i)
239 if (components[i].tag == id)
241 if (tagged_components == 0)
243 // Only allocate a sequence if we have tagged components
244 // to place into the sequence.
245 ACE_NEW_THROW_EX (tagged_components,
246 IOP::TaggedComponentSeq,
247 CORBA::NO_MEMORY (
248 CORBA::SystemException::_tao_minor_code (
249 TAO::VMCID,
250 ENOMEM),
251 CORBA::COMPLETED_NO));
253 safe_tagged_components = tagged_components;
256 const CORBA::ULong old_len = safe_tagged_components->length ();
257 safe_tagged_components->length (old_len + 1);
259 safe_tagged_components[old_len] = components[i]; // Deep copy
263 if (tagged_components == 0)
265 // No tagged component sequence was allocated, meaning no tagged
266 // components were found that matched the given
267 // IOP::ComponentId.
268 throw ::CORBA::BAD_PARAM (CORBA::OMGVMCID | 28, CORBA::COMPLETED_NO);
271 return safe_tagged_components._retn ();
274 CORBA::Policy_ptr
275 TAO_ClientRequestInfo::get_request_policy (CORBA::PolicyType type)
277 this->check_validity ();
279 // @@ Do we need to look anywhere else for the request policies?
281 #if TAO_HAS_CORBA_MESSAGING == 1
282 return this->invocation_->target ()->_get_policy (type);
283 #else
284 ACE_UNUSED_ARG (type);
286 throw ::CORBA::NO_IMPLEMENT (
287 CORBA::SystemException::_tao_minor_code (
288 TAO::VMCID,
289 ENOTSUP),
290 CORBA::COMPLETED_NO);
291 #endif /* TAO_HAS_CORBA_MESSAGING == 1 */
294 void
295 TAO_ClientRequestInfo::add_request_service_context (
296 const IOP::ServiceContext & service_context,
297 CORBA::Boolean replace)
299 this->check_validity ();
301 // Get the service context from the list
302 TAO_Service_Context &service_context_list =
303 this->invocation_->request_service_context ();
305 if (service_context_list.set_context (service_context, replace) == 0)
307 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 15, CORBA::COMPLETED_NO);
311 CORBA::ULong
312 TAO_ClientRequestInfo::request_id ()
314 this->check_validity ();
316 // @todo We may have to worry about AMI once we support interceptors
317 // in AMI requests since the Invocation object no longer
318 // exists once an AMI request has been made. In that case,
319 // the reply dispatcher address should be used.
321 // The request ID must be unique across all outstanding requests.
322 // To avoid synchronization overhead, the address of this Invocation
323 // object is used as the request ID. This guarantees that the
324 // request ID is unique without being forced to acquire a lock.
326 // For 64-bit platforms, we right shift 8 bits and then use the
327 // lower 32 bits of that shifted value. Rather than losing the
328 // upper 32 bits of significant digits by taking the lower 32 bits,
329 // we only lose the upper 24 by doing the shift. Basically, the
330 // resulting request ID will comprised of bits 8 through 39. This is
331 // made possible by the fact that this Invocation object is large
332 // enough to increase the likelihood that those bits (0 through 39)
333 // are unique. In particular, this->buffer_ is 512 bytes
334 // (ACE_CDR::DEFAULT_BUFSIZE) long by default; implying that
335 // dropping the lower 8 bits of the this Invocation object's 64 bit
336 // address (i.e. 256 bytes) is not a problem.
338 CORBA::ULong id = 0;
340 // Note that we reinterpret_cast to an "unsigned long" instead of
341 // CORBA::ULong since we need to first cast to an integer large
342 // enough to hold an address to avoid compile-time warnings on some
343 // 64-bit platforms.
345 // 32 bit address
346 if (sizeof (this) == 4)
347 id =
348 static_cast<CORBA::ULong> (
349 reinterpret_cast<ptrdiff_t> (this->invocation_));
351 // 64 bit address -- bits 8 through 39 (see notes above!)
352 // In this case, we make sure this object is large enough to safely
353 // do the right shift. This is necessary since the size of the
354 // buffer that makes this object is configurable.
355 else if (sizeof (this) == 8
356 && sizeof (*(this->invocation_)) > 256 /* 2 << 8 */)
357 id =
358 (static_cast<CORBA::ULong> (
359 reinterpret_cast<ptrdiff_t> (this->invocation_)) >> 8) & 0xFFFFFFFFu;
361 // 64 bit address -- lower 32 bits
362 else if (sizeof (this) == 8)
363 id =
364 static_cast<CORBA::ULong> (
365 reinterpret_cast<ptrdiff_t> (this->invocation_)) & 0xFFFFFFFFu;
367 // @@ The following request ID generator prevents the
368 // PortableInterceptor::ClientRequestInterceptor::send_request()
369 // interception point from occurring before the call to connect,
370 // thus preventing us from adding an optimization that itself
371 // prevents a connection from being unnecessarily performed.
372 // Thus, the ClientRequestInfo object is forced to have its own
373 // request ID generator in order to make it possible to implement
374 // the above optimization.
376 // Ideally, this request ID generator should go away, especially
377 // since it adds a lock to the critical path.
378 // else // Fallback
379 // id = this->invocation_->request_id ();
381 else
383 if (TAO_debug_level > 0)
384 TAOLIB_ERROR ((LM_ERROR,
385 "(%P|%t) ClientRequestInfo::request_id() failed\n"
386 "(%P|%t) since its request ID generator is not\n"
387 "(%P|%t) supported on this platform.\n"));
389 throw ::CORBA::INTERNAL ();
392 return id;
395 char *
396 TAO_ClientRequestInfo::operation ()
398 this->check_validity ();
400 return CORBA::string_dup (this->invocation_->operation_details ().opname ());
403 Dynamic::ParameterList *
404 TAO_ClientRequestInfo::arguments ()
406 this->check_validity ();
408 // Generate the argument list on demand.
409 Dynamic::ParameterList *parameter_list =
410 TAO_RequestInfo_Util::make_parameter_list ();
412 Dynamic::ParameterList_var safe_parameter_list = parameter_list;
414 if (this->parameter_list (*parameter_list) == false)
415 throw ::CORBA::MARSHAL ();
417 return safe_parameter_list._retn ();
420 bool
421 TAO_ClientRequestInfo::parameter_list (Dynamic::ParameterList &param_list)
423 // Account for the return type that is in the argument list.
424 param_list.length (this->invocation_->operation_details ().args_num () - 1);
426 for (CORBA::ULong i = 1; i != this->invocation_->operation_details ().args_num (); ++i)
428 TAO::Argument *argument =
429 this->invocation_->operation_details ().args ()[i];
430 Dynamic::Parameter &p = param_list[i - 1];
431 p.mode = argument->mode ();
432 // When we are in send_request and have an out argument, then
433 // don't copy it, just let the any be empty with typecode tk_null
434 if ((this->invocation_->invoke_status () != TAO::TAO_INVOKE_START) ||
435 (this->invocation_->invoke_status () == TAO::TAO_INVOKE_START &&
436 argument->mode () != CORBA::PARAM_OUT))
438 argument->interceptor_value (&p.argument);
442 return true;
445 Dynamic::ExceptionList *
446 TAO_ClientRequestInfo::exceptions ()
448 this->check_validity ();
450 Dynamic::ExceptionList *exception_list =
451 TAO_RequestInfo_Util::make_exception_list ();
453 Dynamic::ExceptionList_var safe_exception_list = exception_list;
455 if (this->exception_list (*exception_list) == false)
456 throw ::CORBA::MARSHAL ();
458 return safe_exception_list._retn ();
461 bool
462 TAO_ClientRequestInfo::exception_list (Dynamic::ExceptionList &exception_list)
464 if (this->invocation_->operation_details ().ex_count ())
466 exception_list.length (this->invocation_->operation_details ().ex_count ());
468 for (CORBA::ULong i = 0;
469 i != this->invocation_->operation_details ().ex_count ();
470 ++i)
472 CORBA::TypeCode_ptr tcp =
473 this->invocation_->operation_details ().ex_data ()[i].tc_ptr;
474 if (!CORBA::is_nil (tcp))
476 exception_list[i] = tcp;
480 return true;
483 Dynamic::ContextList *
484 TAO_ClientRequestInfo::contexts ()
486 this->check_validity ();
488 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
491 Dynamic::RequestContext *
492 TAO_ClientRequestInfo::operation_context ()
494 this->check_validity ();
496 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
499 CORBA::Any *
500 TAO_ClientRequestInfo::result ()
502 this->check_validity ();
504 // Generate the result on demand.
505 static const CORBA::Boolean tk_void_any = 0;
506 CORBA::Any *result_any =
507 TAO_RequestInfo_Util::make_any (tk_void_any);
509 CORBA::Any_var safe_result_any = result_any;
511 if (this->result (result_any) == false)
512 throw ::CORBA::MARSHAL ();
514 return safe_result_any._retn ();
517 bool
518 TAO_ClientRequestInfo::result (CORBA::Any *any)
520 // Result is always first element in TAO::Argument array.
521 TAO::Argument * const r = this->invocation_->operation_details ().args ()[0];
523 r->interceptor_value (any);
525 return true;
528 CORBA::Boolean
529 TAO_ClientRequestInfo::response_expected ()
531 this->check_validity ();
533 return this->invocation_->response_expected ();
536 Messaging::SyncScope
537 TAO_ClientRequestInfo::sync_scope ()
539 this->check_validity ();
541 return this->invocation_->operation_details ().response_flags ();
544 PortableInterceptor::ReplyStatus
545 TAO_ClientRequestInfo::reply_status ()
547 this->check_validity ();
549 PortableInterceptor::ReplyStatus const status =
550 this->invocation_->pi_reply_status();
551 if (status == -1 || status == PortableInterceptor::UNKNOWN)
553 // A reply hasn't been received yet.
554 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
557 return status;
560 CORBA::Object_ptr
561 TAO_ClientRequestInfo::forward_reference ()
563 this->check_validity ();
565 if (this->invocation_->pi_reply_status() != PortableInterceptor::LOCATION_FORWARD)
567 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
570 // TAO::Invocation_Base::forward_reference() already duplicates the
571 // reference before returning it so there is no need to duplicate it
572 // here.
573 return this->invocation_->forwarded_reference ();
576 CORBA::Any *
577 TAO_ClientRequestInfo::get_slot (PortableInterceptor::SlotId id)
579 this->check_validity ();
581 return this->rs_pi_current_.get_slot (id);
584 IOP::ServiceContext *
585 TAO_ClientRequestInfo::get_request_service_context (IOP::ServiceId id)
587 this->check_validity ();
589 // Get the service context from the list
590 TAO_Service_Context &service_context_list =
591 this->invocation_->request_service_context ();
593 return this->get_service_context_i (service_context_list, id);
596 IOP::ServiceContext *
597 TAO_ClientRequestInfo::get_reply_service_context (IOP::ServiceId id)
599 this->check_validity ();
601 // Get the service context from the list
602 TAO_Service_Context &service_context_list =
603 this->invocation_->reply_service_context ();
605 return this->get_service_context_i (service_context_list, id);
608 void
609 TAO_ClientRequestInfo::check_validity ()
611 if (this->invocation_ == 0)
612 throw ::CORBA::BAD_INV_ORDER (CORBA::OMGVMCID | 14, CORBA::COMPLETED_NO);
615 void
616 TAO_ClientRequestInfo::tao_ft_expiration_time (TimeBase::TimeT time)
618 this->invocation_->operation_details ().ft_expiration_time (time);
621 TimeBase::TimeT
622 TAO_ClientRequestInfo::tao_ft_expiration_time () const
624 return this->invocation_->operation_details ().ft_expiration_time ();
627 void
628 TAO_ClientRequestInfo::tao_ft_retention_id (CORBA::Long request_id)
630 this->invocation_->operation_details ().ft_retention_id (request_id) ;
633 CORBA::Long
634 TAO_ClientRequestInfo::tao_ft_retention_id () const
636 return this->invocation_->operation_details ().ft_retention_id ();
639 TAO_END_VERSIONED_NAMESPACE_DECL
641 #endif /* TAO_HAS_INTERCEPTORS == 1 */