< Summary

Information
Class: Ice.Communicator
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Communicator.cs
Tag: 71_18251537082
Line coverage
94%
Covered lines: 85
Uncovered lines: 5
Coverable lines: 90
Total lines: 469
Line coverage: 94.4%
Branch coverage
83%
Covered branches: 10
Total branches: 12
Branch coverage: 83.3%
Method coverage
94%
Covered methods: 36
Total methods: 38
Method coverage: 94.7%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_shutdownCompleted()100%11100%
get_instance()100%11100%
Dispose()100%11100%
DisposeAsync()100%11100%
destroy()100%11100%
shutdown()100%11100%
waitForShutdown()100%11100%
isShutdown()100%11100%
stringToProxy(...)100%22100%
proxyToString(...)50%22100%
propertyToProxy(...)100%22100%
proxyToProperty(...)100%11100%
identityToString(...)100%11100%
createObjectAdapter(...)100%11100%
createObjectAdapterWithEndpoints(...)50%2.06275%
createObjectAdapterWithRouter(...)100%44100%
getDefaultObjectAdapter()100%11100%
setDefaultObjectAdapter(...)100%11100%
getImplicitContext()100%11100%
getProperties()100%11100%
getLogger()100%11100%
addSliceLoader(...)100%210%
getObserver()100%210%
getDefaultRouter()100%11100%
setDefaultRouter(...)100%11100%
getDefaultLocator()100%11100%
setDefaultLocator(...)100%11100%
getPluginManager()100%11100%
flushBatchRequests(...)100%1.02175%
flushBatchRequestsAsync(...)100%11100%
createAdmin(...)100%11100%
getAdmin()100%11100%
addAdminFacet(...)100%11100%
removeAdminFacet(...)100%11100%
findAdminFacet(...)100%11100%
findAllAdminFacets()100%11100%
.ctor(...)100%11100%
finishSetup()100%11100%

File(s)

/home/runner/work/ice/ice/csharp/src/Ice/Communicator.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3#nullable enable
 4
 5using Ice.Internal;
 6using System.Net.Security;
 7
 8namespace Ice;
 9
 10public sealed class Communicator : IDisposable, IAsyncDisposable
 11{
 12    /// <summary>
 13    /// Gets a task that completes when the communicator's shutdown completes. This task always completes successfully.
 14    /// </summary>
 15    /// <remarks>The shutdown of a communicator completes when all its incoming connections are closed. Awaiting this
 16    /// task is equivalent to calling <see cref="waitForShutdown" />.</remarks>
 17    /// <seealso cref="shutdown" />
 18    public Task shutdownCompleted
 19    {
 20        get
 21        {
 22            // It would be much nicer to wait asynchronously but doing so requires significant refactoring.
 123            var tcs = new TaskCompletionSource(); // created "on demand", when the user calls shutdownCompleted
 124            _ = Task.Run(() =>
 125            {
 126                waitForShutdown();
 127                tcs.SetResult();
 128            });
 129            return tcs.Task;
 30        }
 31    }
 32
 133    internal Instance instance { get; }
 34
 35    private const string _flushBatchRequests_name = "flushBatchRequests";
 36
 37    /// <summary>
 38    /// Disposes this communicator. It's an alias for <see cref="destroy"/>.
 39    /// </summary>
 140    public void Dispose() => destroy();
 41
 42    /// <summary>
 43    /// Disposes this communicator asynchronously. Like <see cref="Communicator.shutdownCompleted" />, this method
 44    /// waits for all outstanding dispatches to complete.
 45    /// </summary>
 46    /// <returns>A task that completes when the communicator is disposed.</returns>
 47    public ValueTask DisposeAsync()
 48    {
 49        // A truly async implementation would be nicer but requires significant refactoring.
 150        var tcs = new TaskCompletionSource();
 151        _ = Task.Run(() =>
 152        {
 153            Dispose(); // can block for a while
 154            tcs.SetResult();
 155        });
 56
 157        return new(tcs.Task);
 58    }
 59
 60    /// <summary>
 61    /// Destroys the communicator. This method calls <see cref="shutdown" /> implicitly. Calling destroy destroys all
 62    /// object adapters, and closes all outgoing connections. This method waits for all outstanding dispatches to
 63    /// complete before returning. This includes "bidirectional dispatches" that execute on outgoing connections.
 64    /// </summary>
 165    public void destroy() => instance.destroy();
 66
 67    /// <summary>
 68    /// Shuts down this communicator: call <see cref="ObjectAdapter.deactivate"/> on all object adapters created by
 69    /// this communicator. Shutting down a communicator has no effect on outgoing connections.
 70    /// </summary>
 71    public void shutdown()
 72    {
 73        try
 74        {
 175            instance.objectAdapterFactory().shutdown();
 176        }
 177        catch (CommunicatorDestroyedException)
 78        {
 79            // Ignore
 180        }
 181    }
 82
 83    /// <summary>
 84    /// Waits for the shutdown of this communicator to complete.
 85    /// This method calls <see cref="ObjectAdapter.waitForDeactivate" /> on all object adapters created by this
 86    /// communicator. In a client application that does not accept incoming connections, this method returns as soon as
 87    /// another thread calls <see cref="shutdown" /> or <see cref="destroy" /> on this communicator.
 88    /// </summary>
 89    public void waitForShutdown()
 90    {
 91        try
 92        {
 193            instance.objectAdapterFactory().waitForShutdown();
 194        }
 195        catch (CommunicatorDestroyedException)
 96        {
 97            // Ignore
 198        }
 199    }
 100
 101    /// <summary>
 102    /// Checks whether or not <see cref="shutdown" /> was called on this communicator.
 103    /// </summary>
 104    /// <returns>True if shutdown was called on this communicator; false otherwise.</returns>
 105    public bool isShutdown()
 106    {
 107        try
 108        {
 1109            return instance.objectAdapterFactory().isShutdown();
 110        }
 1111        catch (CommunicatorDestroyedException)
 112        {
 1113            return true;
 114        }
 1115    }
 116
 117    /// <summary>
 118    /// Converts a stringified proxy into a proxy.
 119    /// For example, "MyCategory/MyObject:tcp -h some_host -p 10000" creates a proxy that refers to the Ice object
 120    /// having an identity with a name "MyObject" and a category "MyCategory", with the server running on host
 121    /// "some_host", port 10000. If the stringified proxy does not parse correctly, this method throws ParseException.
 122    /// Refer to the Ice manual for a detailed description of the syntax supported by stringified proxies.
 123    /// </summary>
 124    /// <param name="str">The stringified proxy to convert into a proxy.</param>
 125    /// <returns>The proxy, or null if str is an empty string.</returns>
 126    public ObjectPrx? stringToProxy(string str)
 127    {
 1128        Reference? reference = instance.referenceFactory().create(str, "");
 1129        return reference is not null ? new ObjectPrxHelper(reference) : null;
 130    }
 131
 132    /// <summary>
 133    /// Converts a proxy into a string.
 134    /// </summary>
 135    /// <param name="proxy">The proxy to convert into a stringified proxy.</param>
 136    /// <returns>The stringified proxy, or an empty string if <paramref name="proxy" /> is null.</returns>
 137    public string proxyToString(ObjectPrx? proxy) =>
 1138        proxy is null ? "" : ((ObjectPrxHelperBase)proxy).iceReference().ToString();
 139
 140    /// <summary>
 141    /// Converts a set of proxy properties into a proxy. The "base" name supplied in the <paramref name="property" />
 142    /// argument refers to a property containing a stringified proxy, such as `MyProxy=id:tcp -h localhost -p 10000`.
 143    /// Additional properties configure local settings for the proxy.
 144    /// </summary>
 145    ///
 146    /// <param name="property">The base property name.</param>
 147    /// <returns>The proxy, or <c>null</c> if the property is not set.</returns>
 148    public ObjectPrx? propertyToProxy(string property)
 149    {
 1150        string proxy = instance.initializationData().properties!.getProperty(property);
 1151        Reference? reference = instance.referenceFactory().create(proxy, property);
 1152        return reference is not null ? new ObjectPrxHelper(reference) : null;
 153    }
 154
 155    /// <summary>
 156    /// Converts a proxy to a set of proxy properties.
 157    /// </summary>
 158    /// <param name="proxy">The proxy.</param>
 159    /// <param name="prefix">The base property name.</param>
 160    /// <returns>The property set.</returns>
 161    public Dictionary<string, string> proxyToProperty(ObjectPrx proxy, string prefix) =>
 1162        ((ObjectPrxHelperBase)proxy).iceReference().toProperty(prefix);
 163
 164    /// <summary>
 165    /// Converts an identity into a string.
 166    /// </summary>
 167    /// <param name="ident">The identity to convert into a string.</param>
 168    /// <returns>The "stringified" identity.</returns>
 1169    public string identityToString(Identity ident) => Util.identityToString(ident, instance.toStringMode());
 170
 171    /// <summary>Creates a new object adapter. The endpoints for the object adapter are taken from the property
 172    /// name.Endpoints. It is legal to create an object adapter with the empty string as its name. Such an object
 173    /// adapter is accessible via bidirectional connections or by collocated invocations that originate from the
 174    /// same communicator as is used by the adapter. Attempts to create a named object adapter for which no
 175    /// configuration can be found raise InitializationException.</summary>
 176    /// <param name="name">The object adapter name.</param>
 177    /// <param name="serverAuthenticationOptions">The authentication options used by the SSL transport. Pass null
 178    /// if the adapter doesn't have any secure endpoints or if the SSL transport is configured using IceSSL properties.
 179    /// When <paramref name="serverAuthenticationOptions"/> is set to a non-null value, all IceSSL properties are
 180    /// ignored, and all the required configuration must be set using the <see cref="SslServerAuthenticationOptions"/>
 181    /// object.
 182    /// </param>
 183    /// <returns>The new object adapter.</returns>
 184    public ObjectAdapter createObjectAdapter(
 185        string name,
 186        SslServerAuthenticationOptions? serverAuthenticationOptions = null) =>
 1187        instance.objectAdapterFactory().createObjectAdapter(name, null, serverAuthenticationOptions);
 188
 189    /// <summary>Creates a new object adapter with endpoints. This method sets the property name.Endpoints, and
 190    /// then calls createObjectAdapter. It is provided as a convenience function. Calling this operation with an
 191    /// empty name will result in a UUID being generated for the name.</summary>
 192    /// <param name="name">The object adapter name.</param>
 193    /// <param name="endpoints">The endpoints for the object adapter.</param>
 194    /// <param name="serverAuthenticationOptions">The authentication options used by the SSL transport. Pass null
 195    /// if the adapter doesn't have any secure endpoints or if the SSL transport is configured using IceSSL properties.
 196    /// When <paramref name="serverAuthenticationOptions"/> is set to a non-null value, all IceSSL properties are
 197    /// ignored, and all the required configuration must be set using the <see cref="SslServerAuthenticationOptions"/>
 198    /// object.</param>
 199    /// <returns>The new object adapter.</returns>
 200    public ObjectAdapter createObjectAdapterWithEndpoints(
 201        string name,
 202        string endpoints,
 203        SslServerAuthenticationOptions? serverAuthenticationOptions = null)
 204    {
 1205        if (name.Length == 0)
 206        {
 0207            name = Guid.NewGuid().ToString();
 208        }
 209
 1210        getProperties().setProperty(name + ".Endpoints", endpoints);
 1211        return instance.objectAdapterFactory().createObjectAdapter(name, null, serverAuthenticationOptions);
 212    }
 213
 214    /// <summary>
 215    /// Creates a new object adapter with a router.
 216    /// This method creates a routed object adapter. Calling this operation with an empty name will result in a UUID
 217    /// being generated for the name.
 218    /// </summary>
 219    /// <param name="name">The object adapter name.</param>
 220    /// <param name="router">The router.</param>
 221    /// <returns>The new object adapter.</returns>
 222    public ObjectAdapter createObjectAdapterWithRouter(string name, RouterPrx router)
 223    {
 1224        if (name.Length == 0)
 225        {
 1226            name = Guid.NewGuid().ToString();
 227        }
 228
 229        //
 230        // We set the proxy properties here, although we still use the proxy supplied.
 231        //
 1232        Dictionary<string, string> properties = proxyToProperty(router, name + ".Router");
 1233        foreach (KeyValuePair<string, string> entry in properties)
 234        {
 1235            getProperties().setProperty(entry.Key, entry.Value);
 236        }
 237
 1238        return instance.objectAdapterFactory().createObjectAdapter(name, router, serverAuthenticationOptions: null);
 239    }
 240
 241    /// <summary>
 242    /// Gets the object adapter that is associated by default with new outgoing connections created by this
 243    /// communicator. This method returns null unless you set a non-null default object adapter using
 244    /// <see cref="setDefaultObjectAdapter" />.
 245    /// </summary>
 246    /// <returns>The object adapter associated by default with new outgoing connections.</returns>
 247    /// <seealso cref="Connection.getAdapter" />
 1248    public ObjectAdapter? getDefaultObjectAdapter() => instance.outgoingConnectionFactory().getDefaultObjectAdapter();
 249
 250    /// <summary>
 251    /// Sets the object adapter that will be associated with new outgoing connections created by this communicator. This
 252    /// method has no effect on existing outgoing connections, or on incoming connections.
 253    /// </summary>
 254    /// <param name="adapter">The object adapter to associate with new outgoing connections.</param>
 255    /// <seealso cref="Connection.setAdapter" />
 256    public void setDefaultObjectAdapter(ObjectAdapter? adapter) =>
 1257        instance.outgoingConnectionFactory().setDefaultObjectAdapter(adapter);
 258
 259    /// <summary>
 260    /// Gets the implicit context associated with this communicator.
 261    /// </summary>
 262    /// <returns>The implicit context associated with this communicator; returns null when the property
 263    /// Ice.ImplicitContext is not set or is set to None.</returns>
 1264    public ImplicitContext getImplicitContext() => instance.getImplicitContext();
 265
 266    /// <summary>
 267    /// Gets the properties for this communicator.
 268    /// </summary>
 269    /// <returns>This communicator's properties.</returns>
 1270    public Properties getProperties() => instance.initializationData().properties!;
 271
 272    /// <summary>
 273    /// Gets the logger for this communicator.
 274    /// </summary>
 275    /// <returns>This communicator's logger.</returns>
 1276    public Logger getLogger() => instance.initializationData().logger!;
 277
 278    /// <summary>
 279    /// Adds a Slice loader to this communicator, after the Slice loader set in <see cref="InitializationData" />(if
 280    /// any) and after other Slice loaders added by this method.
 281    /// </summary>
 282    /// <param name="loader"> The Slice loader to add.</param>
 283    /// <remarks>This method is not thread-safe and should only be called right after the communicator is created.
 284    /// It's provided for applications that cannot set the Slice loader in the <see cref="InitializationData" /> of the
 285    /// communicator, such as IceBox services.</remarks>
 0286    public void addSliceLoader(SliceLoader loader) => instance.addSliceLoader(loader);
 287
 288    /// <summary>
 289    /// Gets the observer resolver object for this communicator.
 290    /// </summary>
 291    /// <returns>This communicator's observer resolver object.</returns>
 0292    public Instrumentation.CommunicatorObserver? getObserver() => instance.initializationData().observer;
 293
 294    /// <summary>
 295    /// Gets the default router for this communicator.
 296    /// </summary>
 297    /// <returns>The default router for this communicator.</returns>
 1298    public RouterPrx? getDefaultRouter() => instance.referenceFactory().getDefaultRouter();
 299
 300    /// <summary>
 301    /// Sets a default router for this communicator.
 302    /// All newly created proxies will use this default router. To disable the default router, null can be used. Note
 303    /// that this method has no effect on existing proxies. You can also set a router for an individual proxy by calling
 304    /// <see cref="ObjectPrx.ice_router(RouterPrx?)" /> on the proxy.
 305    /// </summary>
 306    /// <param name="router">The default router to use for this communicator.</param>
 1307    public void setDefaultRouter(RouterPrx? router) => instance.setDefaultRouter(router);
 308
 309    /// <summary>
 310    /// Gets the default locator for this communicator.
 311    /// </summary>
 312    /// <returns>The default locator for this communicator.</returns>
 1313    public LocatorPrx? getDefaultLocator() => instance.referenceFactory().getDefaultLocator();
 314
 315    /// <summary>
 316    /// Sets a default Ice locator for this communicator.
 317    /// All newly created proxy and object adapters will use this default locator. To disable the default locator, null
 318    /// can be used. Note that this method has no effect on existing proxies or object adapters.
 319    /// You can also set a locator for an individual proxy by calling <see cref="ObjectPrx.ice_locator(LocatorPrx?)" />
 320    /// on the proxy, or for an object adapter by calling <see cref="ObjectAdapter.setLocator(LocatorPrx)" /> on the
 321    /// object adapter.
 322    /// </summary>
 323    /// <param name="locator">The default locator to use for this communicator.</param>
 1324    public void setDefaultLocator(LocatorPrx? locator) => instance.setDefaultLocator(locator);
 325
 326    /// <summary>
 327    /// Gets the plug-in manager for this communicator.
 328    /// </summary>
 329    /// <returns>This communicator's plug-in manager.</returns>
 1330    public PluginManager getPluginManager() => instance.pluginManager();
 331
 332    /// <summary>
 333    /// Flushes any pending batch requests for this communicator.
 334    /// This means all batch requests invoked on fixed proxies for all connections associated with the communicator.
 335    /// Any errors that occur while flushing a connection are ignored.
 336    /// </summary>
 337    /// <param name="compress">Specifies whether or not the queued batch requests should be compressed before being sent
 338    /// over the wire.</param>
 339    public void flushBatchRequests(CompressBatch compress)
 340    {
 341        try
 342        {
 1343            var completed = new FlushBatchTaskCompletionCallback();
 1344            var outgoing = new CommunicatorFlushBatchAsync(instance, completed);
 1345            outgoing.invoke(_flushBatchRequests_name, compress, true);
 1346            completed.Task.Wait();
 1347        }
 0348        catch (AggregateException ex)
 349        {
 0350            throw ex.InnerException!;
 351        }
 1352    }
 353
 354    public Task flushBatchRequestsAsync(
 355        CompressBatch compress,
 356        IProgress<bool>? progress = null,
 357        CancellationToken cancel = default)
 358    {
 1359        var completed = new FlushBatchTaskCompletionCallback(progress, cancel);
 1360        var outgoing = new CommunicatorFlushBatchAsync(instance, completed);
 1361        outgoing.invoke(_flushBatchRequests_name, compress, false);
 1362        return completed.Task;
 363    }
 364
 365    /// <summary>
 366    /// Adds the Admin object with all its facets to the provided object adapter.
 367    /// If Ice.Admin.ServerId is set and the provided object adapter has a Locator, createAdmin registers the Admin's
 368    /// Process facet with the Locator's LocatorRegistry. createAdmin must only be called once; subsequent calls raise
 369    /// InitializationException.
 370    /// </summary>
 371    /// <param name="adminAdapter">The object adapter used to host the Admin object; if null and Ice.Admin.Endpoints is
 372    /// set, create, activate and use the Ice.Admin object adapter.</param>
 373    /// <param name="adminId">The identity of the Admin object.</param>
 374    /// <returns>A proxy to the main ("") facet of the Admin object.</returns>
 375    public ObjectPrx createAdmin(ObjectAdapter adminAdapter, Identity adminId) =>
 1376        instance.createAdmin(adminAdapter, adminId);
 377
 378    /// <summary>
 379    /// Gets a proxy to the main facet of the Admin object.
 380    /// getAdmin also creates the Admin object and creates and activates the Ice.Admin object adapter to host this
 381    /// Admin object if Ice.Admin.Endpoints is set. The identity of the Admin object created by getAdmin is
 382    /// {value of Ice.Admin.InstanceName}/admin, or {UUID}/admin when  Ice.Admin.InstanceName is not set. If
 383    /// Ice.Admin.DelayCreation is 0 or not set, getAdmin is called  by the communicator initialization, after
 384    /// initialization of all plugins.
 385    /// </summary>
 386    /// <returns>A proxy to the main ("") facet of the Admin object, or a null proxy if no Admin object is configured.
 387    /// </returns>
 1388    public ObjectPrx? getAdmin() => instance.getAdmin();
 389
 390    /// <summary>
 391    /// Adds a new facet to the Admin object.
 392    /// Adding a servant with a facet that is already registered throws AlreadyRegisteredException.
 393    /// </summary>
 394    /// <param name="servant">The servant that implements the new Admin facet.</param>
 395    /// <param name="facet">The name of the new Admin facet.</param>
 1396    public void addAdminFacet(Object servant, string facet) => instance.addAdminFacet(servant, facet);
 397
 398    /// <summary>
 399    /// Removes the following facet to the Admin object.
 400    /// Removing a facet that was not previously registered throws <see cref="NotRegisteredException" />.
 401    /// </summary>
 402    /// <param name="facet">The name of the Admin facet.</param>
 403    /// <returns>The servant associated with this Admin facet.</returns>
 1404    public Object removeAdminFacet(string facet) => instance.removeAdminFacet(facet);
 405
 406    /// <summary>
 407    /// Returns a facet of the Admin object.
 408    /// </summary>
 409    /// <param name="facet">The name of the Admin facet.</param>
 410    /// <returns>The servant associated with this Admin facet, or null if no facet is registered with the given name.
 411    /// </returns>
 1412    public Object? findAdminFacet(string facet) => instance.findAdminFacet(facet);
 413
 414    /// <summary>
 415    /// Returns a map of all facets of the Admin object.
 416    /// </summary>
 417    /// <returns>A collection containing all the facet names and servants of the Admin object.</returns>
 1418    public Dictionary<string, Object> findAllAdminFacets() => instance.findAllAdminFacets();
 419
 1420    internal Communicator(InitializationData initData)
 421    {
 1422        instance = new Instance();
 1423        instance.initialize(this, initData);
 1424    }
 425
 426    internal void finishSetup()
 427    {
 428        try
 429        {
 1430            instance.finishSetup(this);
 1431        }
 1432        catch
 433        {
 1434            instance.destroy();
 1435            throw;
 436        }
 1437    }
 438}
 439
 440/// <summary>
 441/// The output mode for xxxToString methods such as identityToString and proxyToString.
 442/// The actual encoding format for
 443/// the string is the same for all modes: you don't need to specify an encoding format or mode when reading such a
 444/// string.
 445/// </summary>
 446public enum ToStringMode
 447{
 448    /// <summary>
 449    /// Characters with ordinal values greater than 127 are kept as-is in the resulting string.
 450    /// Non-printable ASCII
 451    /// characters with ordinal values 127 and below are encoded as \\t, \\n (etc.) or \\unnnn.
 452    /// </summary>
 453    Unicode,
 454
 455    /// <summary>
 456    /// Characters with ordinal values greater than 127 are encoded as universal character names in the resulting
 457    /// string: \\unnnn for BMP characters and \\Unnnnnnnn for non-BMP characters.
 458    /// Non-printable ASCII characters
 459    /// with ordinal values 127 and below are encoded as \\t, \\n (etc.) or \\unnnn.
 460    /// </summary>
 461    ASCII,
 462
 463    /// <summary>
 464    /// Characters with ordinal values greater than 127 are encoded as a sequence of UTF-8 bytes using octal escapes.
 465    /// Characters with ordinal values 127 and below are encoded as \\t, \\n (etc.) or an octal escape. Use this mode
 466    /// to generate strings compatible with Ice 3.6 and earlier.
 467    /// </summary>
 468    Compat
 469}