ICE 3.4.2
[php5-ice-freebsdport.git] / cs / src / Ice / Outgoing.cs
blobbcbdd6c25228e63369fc1224095247c2f920f317
1 // **********************************************************************
2 //
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
4 //
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
7 //
8 // **********************************************************************
10 namespace IceInternal
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)
28 _state = StateUnsent;
29 _sent = false;
30 _handler = handler;
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)
45 _state = StateUnsent;
46 _exception = null;
47 _sent = false;
48 _handler = handler;
50 writeHeader(operation, mode, context);
53 public void reclaim()
55 _is.reset();
56 _os.reset();
59 // Returns true if ok, false if user exception.
60 public bool invoke()
62 Debug.Assert(_state == StateUnsent);
64 _os.endWriteEncaps();
66 switch(_handler.getReference().getMode())
68 case Reference.Mode.ModeTwoway:
70 _state = StateInProgress;
72 Ice.ConnectionI connection = _handler.sendRequest(this);
74 bool timedOut = false;
76 _m.Lock();
77 try
80 // If the request is being sent in the background we first wait for the
81 // sent notification.
83 while(_state != StateFailed && !_sent)
85 _m.Wait();
89 // Wait until the request has completed, or until the request
90 // times out.
92 int timeout = connection.timeout();
93 while(_state == StateInProgress && !timedOut)
95 if(timeout >= 0)
97 _m.TimedWait(timeout);
99 if(_state == StateInProgress)
101 timedOut = true;
104 else
106 _m.Wait();
110 finally
112 _m.Unlock();
115 if(timedOut)
118 // Must be called outside the synchronization of
119 // this object
121 connection.exception(new Ice.TimeoutException());
124 // We must wait until the exception set above has
125 // propagated to this Outgoing object.
127 _m.Lock();
130 while(_state == StateInProgress)
132 _m.Wait();
135 finally
137 _m.Unlock();
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
149 // be repeated.
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).
157 if(!_sent ||
158 _exception is Ice.CloseConnectionException ||
159 _exception is Ice.ObjectNotExistException)
161 throw _exception;
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)
174 return false;
176 else
178 Debug.Assert(_state == StateOK);
179 return true;
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.
192 _m.Lock();
195 while(_state != StateFailed && !_sent)
197 _m.Wait();
200 if(_exception != null)
202 Debug.Assert(!_sent);
203 throw _exception;
206 finally
208 _m.Unlock();
211 return true;
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);
224 return true;
228 Debug.Assert(false);
229 return false;
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();
247 throw ex;
250 public void sent(bool notify)
252 if(notify)
254 _m.Lock();
257 _sent = true;
258 _m.Notify();
260 finally
262 _m.Unlock();
265 else
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.
271 _sent = true;
275 public void finished(BasicStream istr)
277 _m.Lock();
280 Debug.Assert(_handler.getReference().getMode() == Reference.Mode.ModeTwoway); // Only for twoways.
282 Debug.Assert(_state <= StateInProgress);
284 _is.swap(istr);
285 byte replyStatus = _is.readByte();
287 switch(replyStatus)
289 case ReplyStatus.replyOK:
291 _state = StateOK; // The state must be set last, in case there is an exception.
292 break;
295 case ReplyStatus.replyUserException:
297 _state = StateUserException; // The state must be set last, in case there is an exception.
298 break;
301 case ReplyStatus.replyObjectNotExist:
302 case ReplyStatus.replyFacetNotExist:
303 case ReplyStatus.replyOperationNotExist:
305 Ice.RequestFailedException ex = null;
306 switch(replyStatus)
308 case ReplyStatus.replyObjectNotExist:
310 ex = new Ice.ObjectNotExistException();
311 break;
314 case ReplyStatus.replyFacetNotExist:
316 ex = new Ice.FacetNotExistException();
317 break;
320 case ReplyStatus.replyOperationNotExist:
322 ex = new Ice.OperationNotExistException();
323 break;
326 default:
328 Debug.Assert(false);
329 break;
333 ex.id = new Ice.Identity();
334 ex.id.read__(_is);
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];
348 else
350 ex.facet = "";
353 ex.operation = _is.readString();
354 _exception = ex;
356 _state = StateLocalException; // The state must be set last, in case there is an exception.
357 break;
360 case ReplyStatus.replyUnknownException:
361 case ReplyStatus.replyUnknownLocalException:
362 case ReplyStatus.replyUnknownUserException:
364 Ice.UnknownException ex = null;
365 switch(replyStatus)
367 case ReplyStatus.replyUnknownException:
369 ex = new Ice.UnknownException();
370 break;
373 case ReplyStatus.replyUnknownLocalException:
375 ex = new Ice.UnknownLocalException();
376 break;
379 case ReplyStatus.replyUnknownUserException:
381 ex = new Ice.UnknownUserException();
382 break;
385 default:
387 Debug.Assert(false);
388 break;
392 ex.unknown = _is.readString();
393 _exception = ex;
395 _state = StateLocalException; // The state must be set last, in case there is an exception.
396 break;
399 default:
401 _exception = new Ice.UnknownReplyStatusException();
402 _state = StateLocalException;
403 break;
407 _m.Notify();
409 finally
411 _m.Unlock();
415 public void finished(Ice.LocalException ex, bool sent)
417 _m.Lock();
420 Debug.Assert(_state <= StateInProgress);
421 _state = StateFailed;
422 _exception = ex;
423 _sent = sent;
424 _m.Notify();
426 finally
428 _m.Unlock();
432 public BasicStream istr()
434 return _is;
437 public BasicStream ostr()
439 return _os;
442 public void throwUserException()
446 _is.startReadEncaps();
447 _is.throwException();
449 catch(Ice.UserException)
451 _is.endReadEncaps();
452 throw;
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);
465 break;
468 case Reference.Mode.ModeBatchOneway:
469 case Reference.Mode.ModeBatchDatagram:
471 _handler.prepareBatchRequest(_os);
472 break;
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);
488 else
490 string[] facetPath = { facet };
491 _os.writeStringSeq(facetPath);
494 _os.writeString(operation);
496 _os.writeByte((byte)mode);
498 if(context != null)
501 // Explicit context
503 Ice.ContextHelper.write(_os, context);
505 else
508 // Implicit 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);
517 else
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
526 // blobs.
528 _os.startWriteEncaps();
530 catch(Ice.LocalException ex)
532 abort(ex);
536 internal RequestHandler _handler;
537 internal BasicStream _is;
538 internal BasicStream _os;
539 internal bool _sent;
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;
549 private int _state;
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;
561 _sent = false;
562 _os = new BasicStream(instance);
565 public BatchOutgoing(RequestHandler handler)
567 _handler = handler;
568 _sent = false;
569 _os = new BasicStream(handler.getReference().getInstance());
572 public void invoke()
574 Debug.Assert(_handler != null || _connection != null);
576 if(_handler != null && !_handler.flushBatchRequests(this) ||
577 _connection != null && !_connection.flushBatchRequests(this))
579 _m.Lock();
582 while(_exception == null && !_sent)
584 _m.Wait();
587 if(_exception != null)
589 throw _exception;
592 finally
594 _m.Unlock();
599 public void sent(bool notify)
601 if(notify)
603 _m.Lock();
606 _sent = true;
607 _m.Notify();
609 finally
611 _m.Unlock();
614 else
616 _sent = true;
620 public void finished(Ice.LocalException ex, bool sent)
622 _m.Lock();
625 _exception = ex;
626 _m.Notify();
628 finally
630 _m.Unlock();
634 public BasicStream ostr()
636 return _os;
639 private RequestHandler _handler;
640 private Ice.ConnectionI _connection;
641 private BasicStream _os;
642 private bool _sent;
643 private Ice.LocalException _exception;
645 private readonly IceUtilInternal.Monitor _m = new IceUtilInternal.Monitor();