summaryrefslogtreecommitdiff
path: root/TAO/tao/LocateRequest_Invocation.cpp
blob: 940f8347bc8f75a385c553227b14ed86ba128c75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include "LocateRequest_Invocation.h"
#include "Profile_Transport_Resolver.h"
#include "operation_details.h"
#include "Stub.h"
#include "Bind_Dispatcher_Guard.h"
#include "Transport.h"
#include "Synch_Reply_Dispatcher.h"
#include "GIOP_Utils.h"
#include "Profile.h"
#include "ORB_Constants.h"

#include "ace/Countdown_Time.h"

ACE_RCSID (tao,
           LocateRequest_Invocation,
           "$Id$")

namespace TAO
{
  LocateRequest_Invocation::LocateRequest_Invocation (
      CORBA::Object_ptr otarget,
      Profile_Transport_Resolver &resolver,
      TAO_Operation_Details &detail
    )
    : Synch_Twoway_Invocation (otarget,
                               resolver,
                               detail)
  {
  }

  Invocation_Status
  LocateRequest_Invocation::invoke (ACE_Time_Value *max_wait_time
                                    ACE_ENV_ARG_DECL)
    ACE_THROW_SPEC ((CORBA::Exception))
  {
    ACE_Countdown_Time countdown (max_wait_time);

    TAO_Synch_Reply_Dispatcher rd (this->resolver_.stub ()->orb_core (),
                                   this->details_.reply_service_info ());

    // Register a reply dispatcher for this invocation. Use the
    // preallocated reply dispatcher.
    TAO_Bind_Dispatcher_Guard dispatch_guard (this->details_.request_id (),
                                              &rd,
                                              this->resolver_.transport ()->tms ());

    if (dispatch_guard.status () != 0)
      {
        // @@ What is the right way to handle this error? Do we need
        // to call the interceptors in this case?
        this->resolver_.transport ()->close_connection ();

        ACE_THROW_RETURN (CORBA::INTERNAL (TAO::VMCID,
                                           CORBA::COMPLETED_NO),
                          TAO_INVOKE_FAILURE);
      }

    TAO_Target_Specification tspec;
    this->init_target_spec (tspec ACE_ENV_ARG_PARAMETER);
    ACE_CHECK_RETURN (TAO_INVOKE_FAILURE);

    TAO_Transport *transport =
      this->resolver_.transport ();

    TAO_OutputCDR &cdr =
      transport->out_stream ();

    int retval =
      transport->generate_locate_request (tspec,
                                          this->details_,
                                          cdr);
    ACE_CHECK_RETURN (TAO_INVOKE_FAILURE);

    if (retval == -1)
      return TAO_INVOKE_FAILURE;

    countdown.update ();

    Invocation_Status s =
      this->send_message (cdr,
                          TAO_Transport::TAO_TWOWAY_REQUEST,
                          max_wait_time
                          ACE_ENV_ARG_PARAMETER);
    ACE_CHECK_RETURN (TAO_INVOKE_FAILURE);

    if (s != TAO_INVOKE_SUCCESS)
      return s;

    countdown.update ();

    // For some strategies one may want to release the transport
    // back to  cache. If the idling is successfull let the
    // resolver about that.
    if (this->resolver_.transport ()->idle_after_send ())
      this->resolver_.transport_released ();

    s =
      this->wait_for_reply (max_wait_time,
                            rd,
                            dispatch_guard
                            ACE_ENV_ARG_PARAMETER);
    ACE_CHECK_RETURN (TAO_INVOKE_FAILURE);

    s = this->check_reply (rd
                           ACE_ENV_ARG_PARAMETER);
    ACE_CHECK_RETURN (TAO_INVOKE_FAILURE);

    // For some strategies one may want to release the transport
    // back to  cache after receiving the reply. If the idling is
    // successfull let the resolver about that.
    if (this->resolver_.transport ()->idle_after_reply ())
      this->resolver_.transport_released ();

    return s;
  }

  Invocation_Status
  LocateRequest_Invocation::check_reply (TAO_Synch_Reply_Dispatcher &rd
                                         ACE_ENV_ARG_DECL)
  {
    TAO_InputCDR &cdr =
      rd.reply_cdr ();

    // Set the translators
    this->resolver_.transport ()->assign_translators (&cdr, 0);

    switch (rd.reply_status ())
      {
      case TAO_GIOP_OBJECT_HERE:
        break;
      case TAO_GIOP_UNKNOWN_OBJECT:
        ACE_THROW_RETURN (CORBA::OBJECT_NOT_EXIST (TAO::VMCID,
                                                   CORBA::COMPLETED_YES),
                          TAO_INVOKE_FAILURE);
      case TAO_GIOP_OBJECT_FORWARD:
      case TAO_GIOP_OBJECT_FORWARD_PERM:
        return this->location_forward (cdr
                                       ACE_ENV_ARG_PARAMETER);

      case TAO_GIOP_LOC_SYSTEM_EXCEPTION:
        {
          // Pull the exception from the stream.
          CORBA::String_var buf;

          if ((cdr >> buf.inout ()) == 0)
            {
              // Could not demarshal the exception id, raise a local
              // CORBA::MARSHAL exception.
              ACE_THROW_RETURN (CORBA::MARSHAL (TAO::VMCID,
                                                CORBA::COMPLETED_MAYBE),
                                TAO_INVOKE_SYSTEM_EXCEPTION);
            }

          // This kind of exception shouldn't happen with locate requests,
          // but if it does, we turn it into a CORBA::UNKNOWN exception.
          ACE_THROW_RETURN (CORBA::UNKNOWN (TAO::VMCID,
                                            CORBA::COMPLETED_YES),
                            TAO_INVOKE_SYSTEM_EXCEPTION);
        }
      case TAO_GIOP_LOC_NEEDS_ADDRESSING_MODE:
        {
          // We have received an exception with a request to change the
          // addressing mode. First let us read the mode that the
          // server/agent asks for.
          CORBA::Short addr_mode = 0;

          if (cdr.read_short (addr_mode) == 0)
            {
              // Could not demarshal the addressing disposition, raise a local
              // CORBA::MARSHAL exception.
              ACE_THROW_RETURN (CORBA::MARSHAL (TAO::VMCID,
                                                CORBA::COMPLETED_MAYBE),
                                TAO_INVOKE_SUCCESS);
            }

          // Now set this addressing mode in the profile, so that
          // the next invocation need not go through this.
          this->resolver_.profile ()->addressing_mode (addr_mode
                                                       ACE_ENV_ARG_PARAMETER);
          ACE_CHECK_RETURN (TAO_INVOKE_SUCCESS);

          // Restart the invocation.
          return TAO_INVOKE_RESTART;
        }
      }

    return TAO_INVOKE_SUCCESS;
  }
}