// // Copyright (c) ZeroC, Inc. All rights reserved. // using System; using System.Threading.Tasks; using System.Diagnostics; using System.ComponentModel; namespace Ice { /// /// Interface for incoming requests. /// public interface Request { /// /// Returns the {@link Current} object for this the request. /// /// The Current object for this request. Current getCurrent(); } /// /// the base interface for servants. /// public interface Object : ICloneable { /// /// Tests whether this object supports a specific Slice interface. /// /// /// The type ID of the Slice interface to test against. /// The Current object for the invocation. /// True if this object has the interface /// specified by s or derives from the interface specified by s. bool ice_isA(string s, Current current = null); /// /// Tests whether this object can be reached. /// /// The Current object for the invocation. void ice_ping(Current current = null); /// /// Returns the Slice type IDs of the interfaces supported by this object. /// /// The Current object for the invocation. /// The Slice type IDs of the interfaces supported by this object, in base-to-derived /// order. The first element of the returned array is always ::Ice::Object. string[] ice_ids(Current current = null); /// /// Returns the Slice type ID of the most-derived interface supported by this object. /// /// The Current object for the invocation. /// The Slice type ID of the most-derived interface. string ice_id(Current current = null); /// /// Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation /// to a servant (or to another interceptor). /// /// The details of the invocation. /// The task if dispatched asynchronously, null otherwise. Task ice_dispatch(Request request); Task iceDispatch(IceInternal.Incoming inc, Current current); } /// /// Base class for all Slice classes. /// public abstract class ObjectImpl : Object { /// /// Instantiates an Ice object. /// public ObjectImpl() { } /// /// Returns a copy of the object. The cloned object contains field-for-field copies /// of the state. /// /// The cloned object. public object Clone() { return MemberwiseClone(); } private static readonly string[] _ids = { "::Ice::Object" }; /// /// Tests whether this object supports a specific Slice interface. /// /// The type ID of the Slice interface to test against. /// The Current object for the invocation. /// The return value is true if s is ::Ice::Object. public virtual bool ice_isA(string s, Current current = null) { return s.Equals(_ids[0]); } [EditorBrowsable(EditorBrowsableState.Never)] public static Task iceD_ice_isA(Object obj, IceInternal.Incoming inS, Current current) { InputStream istr = inS.startReadParams(); var id = istr.readString(); inS.endReadParams(); var ret = obj.ice_isA(id, current); var ostr = inS.startWriteParams(); ostr.writeBool(ret); inS.endWriteParams(ostr); inS.setResult(ostr); return null; } /// /// Tests whether this object can be reached. /// The Current object for the invocation. /// public virtual void ice_ping(Current current = null) { // Nothing to do. } [EditorBrowsable(EditorBrowsableState.Never)] public static Task iceD_ice_ping(Object obj, IceInternal.Incoming inS, Current current) { inS.readEmptyParams(); obj.ice_ping(current); inS.setResult(inS.writeEmptyParams()); return null; } /// /// Returns the Slice type IDs of the interfaces supported by this object. /// /// The Current object for the invocation. /// An array whose only element is ::Ice::Object. public virtual string[] ice_ids(Current current = null) { return _ids; } [EditorBrowsable(EditorBrowsableState.Never)] public static Task iceD_ice_ids(Object obj, IceInternal.Incoming inS, Current current) { inS.readEmptyParams(); var ret = obj.ice_ids(current); var ostr = inS.startWriteParams(); ostr.writeStringSeq(ret); inS.endWriteParams(ostr); inS.setResult(ostr); return null; } /// /// Returns the Slice type ID of the most-derived interface supported by this object. /// /// The Current object for the invocation. /// The return value is always ::Ice::Object. public virtual string ice_id(Current current = null) { return _ids[0]; } [EditorBrowsable(EditorBrowsableState.Never)] public static Task iceD_ice_id(Object obj, IceInternal.Incoming inS, Current current) { inS.readEmptyParams(); var ret = obj.ice_id(current); var ostr = inS.startWriteParams(); ostr.writeString(ret); inS.endWriteParams(ostr); inS.setResult(ostr); return null; } /// /// Returns the Slice type ID of the interface supported by this object. /// /// The return value is always ::Ice::Object. public static string ice_staticId() { return _ids[0]; } private static readonly string[] _all = new string[] { "ice_id", "ice_ids", "ice_isA", "ice_ping" }; /// /// Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation /// to a servant (or to another interceptor). /// /// The details of the invocation. /// The task if dispatched asynchronously, null otherwise. public virtual Task ice_dispatch(Request request) { var inc = (IceInternal.Incoming)request; inc.startOver(); return iceDispatch(inc, inc.getCurrent()); } [EditorBrowsable(EditorBrowsableState.Never)] public virtual Task iceDispatch(IceInternal.Incoming inc, Current current) { int pos = Array.BinarySearch(_all, current.operation); if(pos < 0) { throw new OperationNotExistException(current.id, current.facet, current.operation); } switch(pos) { case 0: { return iceD_ice_id(this, inc, current); } case 1: { return iceD_ice_ids(this, inc, current); } case 2: { return iceD_ice_isA(this, inc, current); } case 3: { return iceD_ice_ping(this, inc, current); } } Debug.Assert(false); throw new OperationNotExistException(current.id, current.facet, current.operation); } private static string operationModeToString(OperationMode mode) { if(mode == OperationMode.Normal) { return "::Ice::Normal"; } if(mode == OperationMode.Nonmutating) { return "::Ice::Nonmutating"; } if(mode == OperationMode.Idempotent) { return "::Ice::Idempotent"; } return "???"; } public static void iceCheckMode(OperationMode expected, OperationMode received) { if(expected != received) { if(expected == OperationMode.Idempotent && received == OperationMode.Nonmutating) { // // Fine: typically an old client still using the // deprecated nonmutating keyword // } else { MarshalException ex = new MarshalException(); ex.reason = "unexpected operation mode. expected = " + operationModeToString(expected) + " received = " + operationModeToString(received); throw ex; } } } } /// /// Base class for dynamic dispatch servants. A server application /// derives a concrete servant class from Blobject that /// implements the Blobject.ice_invoke method. /// public abstract class Blobject : ObjectImpl { /// /// Dispatch an incoming request. /// /// The encoded in-parameters for the operation. /// The encoded out-paramaters and return value /// for the operation. The return value follows any out-parameters. /// The Current object to pass to the operation. /// If the operation completed successfully, the return value /// is true. If the operation raises a user exception, /// the return value is false; in this case, outParams /// must contain the encoded user exception. If the operation raises an /// Ice run-time exception, it must throw it directly. public abstract bool ice_invoke(byte[] inParams, out byte[] outParams, Current current); [EditorBrowsable(EditorBrowsableState.Never)] public override Task iceDispatch(IceInternal.Incoming inS, Current current) { byte[] inEncaps = inS.readParamEncaps(); byte[] outEncaps; bool ok = ice_invoke(inEncaps, out outEncaps, current); inS.setResult(inS.writeParamEncaps(inS.getAndClearCachedOutputStream(), outEncaps, ok)); return null; } } public abstract class BlobjectAsync : ObjectImpl { public abstract Task ice_invokeAsync(byte[] inEncaps, Current current); [EditorBrowsable(EditorBrowsableState.Never)] public override Task iceDispatch(IceInternal.Incoming inS, Current current) { byte[] inEncaps = inS.readParamEncaps(); var task = ice_invokeAsync(inEncaps, current); var cached = inS.getAndClearCachedOutputStream(); return task.ContinueWith((Task t) => { var ret = t.GetAwaiter().GetResult(); return Task.FromResult(inS.writeParamEncaps(cached, ret.outEncaps, ret.returnValue)); }).Unwrap(); } } }