1 // **********************************************************************
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
8 // **********************************************************************
13 using System
.Collections
.Generic
;
14 using System
.Diagnostics
;
15 using System
.Threading
;
17 public interface OutgoingMessageCallback
19 void sent(bool notify
);
20 void finished(Ice
.LocalException ex
, bool sent
);
23 public class Outgoing
: OutgoingMessageCallback
25 public Outgoing(RequestHandler handler
, string operation
, Ice
.OperationMode mode
,
26 Dictionary
<string, string> context
)
32 Instance instance
= _handler
.getReference().getInstance();
33 _is
= new BasicStream(instance
);
34 _os
= new BasicStream(instance
);
36 writeHeader(operation
, mode
, context
);
40 // These functions allow this object to be reused, rather than reallocated.
42 public void reset(RequestHandler handler
, string operation
, Ice
.OperationMode mode
,
43 Dictionary
<string, string> context
)
50 writeHeader(operation
, mode
, context
);
59 // Returns true if ok, false if user exception.
62 Debug
.Assert(_state
== StateUnsent
);
66 switch(_handler
.getReference().getMode())
68 case Reference
.Mode
.ModeTwoway
:
70 _state
= StateInProgress
;
72 Ice
.ConnectionI connection
= _handler
.sendRequest(this);
74 bool timedOut
= false;
80 // If the request is being sent in the background we first wait for the
83 while(_state
!= StateFailed
&& !_sent
)
89 // Wait until the request has completed, or until the request
92 int timeout
= connection
.timeout();
93 while(_state
== StateInProgress
&& !timedOut
)
97 _m
.TimedWait(timeout
);
99 if(_state
== StateInProgress
)
118 // Must be called outside the synchronization of
121 connection
.exception(new Ice
.TimeoutException());
124 // We must wait until the exception set above has
125 // propagated to this Outgoing object.
130 while(_state
== StateInProgress
)
141 if(_exception
!= null)
144 // A CloseConnectionException indicates graceful
145 // server shutdown, and is therefore always repeatable
146 // without violating "at-most-once". That's because by
147 // sending a close connection message, the server
148 // guarantees that all outstanding requests can safely
151 // An ObjectNotExistException can always be retried as
152 // well without violating "at-most-once" (see the
153 // implementation of the checkRetryAfterException
154 // method of the ProxyFactory class for the reasons
155 // why it can be useful).
158 _exception
is Ice
.CloseConnectionException
||
159 _exception
is Ice
.ObjectNotExistException
)
165 // Throw the exception wrapped in a LocalExceptionWrapper,
166 // to indicate that the request cannot be resent without
167 // potentially violating the "at-most-once" principle.
169 throw new LocalExceptionWrapper(_exception
, false);
172 if(_state
== StateUserException
)
178 Debug
.Assert(_state
== StateOK
);
183 case Reference
.Mode
.ModeOneway
:
184 case Reference
.Mode
.ModeDatagram
:
186 _state
= StateInProgress
;
187 if(_handler
.sendRequest(this) != null)
190 // If the handler returns the connection, we must wait for the sent callback.
195 while(_state
!= StateFailed
&& !_sent
)
200 if(_exception
!= null)
202 Debug
.Assert(!_sent
);
214 case Reference
.Mode
.ModeBatchOneway
:
215 case Reference
.Mode
.ModeBatchDatagram
:
218 // For batch oneways and datagrams, the same rules
219 // as for regular oneways and datagrams (see
220 // comment above) apply.
222 _state
= StateInProgress
;
223 _handler
.finishBatchRequest(_os
);
232 public void abort(Ice
.LocalException ex
)
234 Debug
.Assert(_state
== StateUnsent
);
237 // If we didn't finish a batch oneway or datagram request,
238 // we must notify the connection about that we give up
239 // ownership of the batch stream.
241 Reference
.Mode mode
= _handler
.getReference().getMode();
242 if(mode
== Reference
.Mode
.ModeBatchOneway
|| mode
== Reference
.Mode
.ModeBatchDatagram
)
244 _handler
.abortBatchRequest();
250 public void sent(bool notify
)
268 // No synchronization is necessary if called from sendRequest() because the connection
269 // send mutex is locked and no other threads can call on Outgoing until it's released.
275 public void finished(BasicStream istr
)
280 Debug
.Assert(_handler
.getReference().getMode() == Reference
.Mode
.ModeTwoway
); // Only for twoways.
282 Debug
.Assert(_state
<= StateInProgress
);
285 byte replyStatus
= _is
.readByte();
289 case ReplyStatus
.replyOK
:
291 _state
= StateOK
; // The state must be set last, in case there is an exception.
295 case ReplyStatus
.replyUserException
:
297 _state
= StateUserException
; // The state must be set last, in case there is an exception.
301 case ReplyStatus
.replyObjectNotExist
:
302 case ReplyStatus
.replyFacetNotExist
:
303 case ReplyStatus
.replyOperationNotExist
:
305 Ice
.RequestFailedException ex
= null;
308 case ReplyStatus
.replyObjectNotExist
:
310 ex
= new Ice
.ObjectNotExistException();
314 case ReplyStatus
.replyFacetNotExist
:
316 ex
= new Ice
.FacetNotExistException();
320 case ReplyStatus
.replyOperationNotExist
:
322 ex
= new Ice
.OperationNotExistException();
333 ex
.id
= new Ice
.Identity();
337 // For compatibility with the old FacetPath.
339 string[] facetPath
= _is
.readStringSeq();
340 if(facetPath
.Length
> 0)
342 if(facetPath
.Length
> 1)
344 throw new Ice
.MarshalException();
346 ex
.facet
= facetPath
[0];
353 ex
.operation
= _is
.readString();
356 _state
= StateLocalException
; // The state must be set last, in case there is an exception.
360 case ReplyStatus
.replyUnknownException
:
361 case ReplyStatus
.replyUnknownLocalException
:
362 case ReplyStatus
.replyUnknownUserException
:
364 Ice
.UnknownException ex
= null;
367 case ReplyStatus
.replyUnknownException
:
369 ex
= new Ice
.UnknownException();
373 case ReplyStatus
.replyUnknownLocalException
:
375 ex
= new Ice
.UnknownLocalException();
379 case ReplyStatus
.replyUnknownUserException
:
381 ex
= new Ice
.UnknownUserException();
392 ex
.unknown
= _is
.readString();
395 _state
= StateLocalException
; // The state must be set last, in case there is an exception.
401 _exception
= new Ice
.UnknownReplyStatusException();
402 _state
= StateLocalException
;
415 public void finished(Ice
.LocalException ex
, bool sent
)
420 Debug
.Assert(_state
<= StateInProgress
);
421 _state
= StateFailed
;
432 public BasicStream
istr()
437 public BasicStream
ostr()
442 public void throwUserException()
446 _is
.startReadEncaps();
447 _is
.throwException();
449 catch(Ice
.UserException
)
456 private void writeHeader(string operation
, Ice
.OperationMode mode
, Dictionary
<string, string> context
)
458 switch(_handler
.getReference().getMode())
460 case Reference
.Mode
.ModeTwoway
:
461 case Reference
.Mode
.ModeOneway
:
462 case Reference
.Mode
.ModeDatagram
:
464 _os
.writeBlob(IceInternal
.Protocol
.requestHdr
);
468 case Reference
.Mode
.ModeBatchOneway
:
469 case Reference
.Mode
.ModeBatchDatagram
:
471 _handler
.prepareBatchRequest(_os
);
478 _handler
.getReference().getIdentity().write__(_os
);
481 // For compatibility with the old FacetPath.
483 string facet
= _handler
.getReference().getFacet();
484 if(facet
== null || facet
.Length
== 0)
486 _os
.writeStringSeq(null);
490 string[] facetPath
= { facet }
;
491 _os
.writeStringSeq(facetPath
);
494 _os
.writeString(operation
);
496 _os
.writeByte((byte)mode
);
503 Ice
.ContextHelper
.write(_os
, context
);
510 Ice
.ImplicitContextI implicitContext
= _handler
.getReference().getInstance().getImplicitContext();
511 Dictionary
<string, string> prxContext
= _handler
.getReference().getContext();
513 if(implicitContext
== null)
515 Ice
.ContextHelper
.write(_os
, prxContext
);
519 implicitContext
.write(prxContext
, _os
);
524 // Input and output parameters are always sent in an
525 // encapsulation, which makes it possible to forward requests as
528 _os
.startWriteEncaps();
530 catch(Ice
.LocalException ex
)
536 internal RequestHandler _handler
;
537 internal BasicStream _is
;
538 internal BasicStream _os
;
541 private Ice
.LocalException _exception
;
543 private const int StateUnsent
= 0;
544 private const int StateInProgress
= 1;
545 private const int StateOK
= 2;
546 private const int StateUserException
= 3;
547 private const int StateLocalException
= 4;
548 private const int StateFailed
= 5;
551 private readonly IceUtilInternal
.Monitor _m
= new IceUtilInternal
.Monitor();
553 public Outgoing next
; // For use by Ice.ObjectDelM_
556 public class BatchOutgoing
: OutgoingMessageCallback
558 public BatchOutgoing(Ice
.ConnectionI connection
, Instance instance
)
560 _connection
= connection
;
562 _os
= new BasicStream(instance
);
565 public BatchOutgoing(RequestHandler handler
)
569 _os
= new BasicStream(handler
.getReference().getInstance());
574 Debug
.Assert(_handler
!= null || _connection
!= null);
576 if(_handler
!= null && !_handler
.flushBatchRequests(this) ||
577 _connection
!= null && !_connection
.flushBatchRequests(this))
582 while(_exception
== null && !_sent
)
587 if(_exception
!= null)
599 public void sent(bool notify
)
620 public void finished(Ice
.LocalException ex
, bool sent
)
634 public BasicStream
ostr()
639 private RequestHandler _handler
;
640 private Ice
.ConnectionI _connection
;
641 private BasicStream _os
;
643 private Ice
.LocalException _exception
;
645 private readonly IceUtilInternal
.Monitor _m
= new IceUtilInternal
.Monitor();