< Summary

Information
Class: Ice.ObjectAdapter
Assembly: Ice
File(s): /_/csharp/src/Ice/ObjectAdapter.cs
Tag: 91_21789722663
Line coverage
87%
Covered lines: 461
Uncovered lines: 65
Coverable lines: 526
Total lines: 1503
Line coverage: 87.6%
Branch coverage
89%
Covered branches: 172
Total branches: 192
Branch coverage: 89.5%
Method coverage
94%
Covered methods: 54
Total methods: 57
Method coverage: 94.7%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)92.11%39.983888.89%
getName()100%22100%
getCommunicator()100%11100%
activate()100%12.611283.78%
hold()100%22100%
waitForHold()100%22100%
deactivate()80%10.011095.24%
waitForDeactivate()100%66100%
isDeactivated()100%11100%
destroy()83.33%121296.88%
use(...)50%2.06275%
add(...)100%11100%
addFacet(...)100%11100%
addWithUUID(...)100%11100%
addFacetWithUUID(...)100%11100%
addDefaultServant(...)100%11100%
remove(...)100%11100%
removeFacet(...)100%11100%
removeAllFacets(...)100%11100%
removeDefaultServant(...)100%11100%
find(...)100%210%
findFacet(...)100%11100%
findAllFacets(...)100%11100%
findByProxy(...)100%210%
addServantLocator(...)100%11100%
removeServantLocator(...)100%11100%
findServantLocator(...)100%210%
findDefaultServant(...)100%11100%
get_dispatchPipeline()100%11100%
createProxy(...)100%11100%
createDirectProxy(...)100%11100%
createIndirectProxy(...)100%11100%
setLocator(...)100%11100%
getLocator()100%22100%
getEndpoints()100%22100%
getPublishedEndpoints()100%11100%
setPublishedEndpoints(...)83.33%6.84671.43%
isLocal(...)100%88100%
flushAsyncBatchRequests(...)100%22100%
updateConnectionObservers()100%22100%
updateThreadObservers()50%22100%
incDirectCount()100%11100%
decDirectCount()100%22100%
getThreadPool()100%22100%
setAdapterOnConnection(...)100%11100%
messageSizeMax()100%11100%
checkIdentity(...)100%22100%
getServerAuthenticationOptions()100%11100%
newProxy(...)100%44100%
newDirectProxy(...)100%11100%
newIndirectProxy(...)100%11100%
checkForDeactivation()50%2.06275%
checkForDestruction()100%22100%
parseEndpoints(...)95.45%2222100%
computePublishedEndpoints()95%20.022096.3%
updateLocatorRegistry(...)70.83%1002449.09%
createDispatchPipeline()100%22100%

File(s)

/_/csharp/src/Ice/ObjectAdapter.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3#nullable enable
 4
 5using Ice.Instrumentation;
 6using Ice.Internal;
 7using System.Diagnostics;
 8using System.Net;
 9using System.Net.Security;
 10using System.Text;
 11
 12namespace Ice;
 13
 14/// <summary>
 15/// An object adapter is the main server-side Ice API. It has two main purposes:
 16/// <list type="bullet">
 17/// <item>accept incoming connections from clients and dispatch requests received over these connections (see
 18/// <see cref="activate" />); and</item>
 19/// <item>maintain a dispatch pipeline and servants that handle the requests (see <see cref="add" />,
 20/// <see cref="addDefaultServant" />, and <see cref="use" />).</item>
 21/// </list>
 22/// An object adapter can dispatch "bidirectional requests"--requests it receives over an outgoing connection
 23/// instead of a more common incoming connection. It can also dispatch collocated requests (with no connection at
 24/// all).
 25/// </summary>
 26/// <seealso cref="Communicator.createObjectAdapter"/>
 27public sealed class ObjectAdapter
 28{
 29    private const int StateUninitialized = 0; // Just constructed.
 30    private const int StateHeld = 1;
 31    private const int StateActivating = 2;
 32    private const int StateActive = 3;
 33    private const int StateDeactivating = 4;
 34    private const int StateDeactivated = 5;
 35    private const int StateDestroying = 6;
 36    private const int StateDestroyed = 7;
 37
 38    private int _state = StateUninitialized;
 39    private readonly Instance _instance;
 40    private readonly Communicator _communicator;
 41    private ObjectAdapterFactory? _objectAdapterFactory;
 42    private Ice.Internal.ThreadPool? _threadPool;
 43    private readonly ServantManager _servantManager;
 44    private readonly string _name;
 45    private readonly string _id;
 46    private readonly string _replicaGroupId;
 47    private Reference? _reference;
 48    private readonly List<IncomingConnectionFactory> _incomingConnectionFactories;
 49    private RouterInfo? _routerInfo;
 50    private EndpointI[] _publishedEndpoints;
 51    private LocatorInfo? _locatorInfo;
 52    private int _directCount;  // The number of colloc proxies dispatching on this object adapter.
 53    private readonly bool _noConfig;
 54    private readonly int _messageSizeMax;
 55    private readonly SslServerAuthenticationOptions? _serverAuthenticationOptions;
 56
 57    private readonly Lazy<Object> _dispatchPipeline;
 158    private readonly Stack<Func<Object, Object>> _middlewareStack = new();
 59
 160    private readonly object _mutex = new();
 61
 62    /// <summary>
 63    /// Gets the name of this object adapter.
 64    /// </summary>
 65    /// <returns>This object adapter's name.</returns>
 166    public string getName() => _noConfig ? "" : _name;
 67
 68    /// <summary>
 69    /// Gets the communicator that created this object adapter.
 70    /// </summary>
 71    /// <returns>This object adapter's communicator.</returns>
 172    public Communicator getCommunicator() => _communicator;
 73
 74    /// <summary>
 75    /// Starts receiving and dispatching requests received over incoming connections.
 76    /// </summary>
 77    /// <remarks>When this object adapter is an indirect object adapter configured with a locator proxy, this
 78    /// method also registers the object adapter's published endpoints with this locator.</remarks>
 79    /// <seealso cref="deactivate"/>
 80    /// <seealso cref="getLocator"/>
 81    /// <seealso cref="getPublishedEndpoints"/>
 82    public void activate()
 83    {
 184        LocatorInfo? locatorInfo = null;
 185        bool printAdapterReady = false;
 186        bool hasPublishedEndpoints = false;
 87
 188        lock (_mutex)
 89        {
 190            checkForDeactivation();
 91
 92            //
 93            // If we've previously been initialized we just need to activate the
 94            // incoming connection factories and we're done.
 95            //
 196            if (_state != StateUninitialized)
 97            {
 198                foreach (IncomingConnectionFactory icf in _incomingConnectionFactories)
 99                {
 1100                    icf.activate();
 101                }
 1102                _state = StateActive;
 1103                Monitor.PulseAll(_mutex);
 1104                return;
 105            }
 106
 107            //
 108            // One off initializations of the adapter: update the
 109            // locator registry and print the "adapter ready"
 110            // message. We set set state to StateActivating to prevent
 111            // deactivation from other threads while these one off
 112            // initializations are done.
 113            //
 1114            _state = StateActivating;
 115
 1116            locatorInfo = _locatorInfo;
 1117            if (!_noConfig)
 118            {
 1119                Properties properties = _instance.initializationData().properties!;
 1120                printAdapterReady = properties.getIcePropertyAsInt("Ice.PrintAdapterReady") > 0;
 121            }
 122
 123            // We contact the locator registry once when this object adapter has one or more published endpoints.
 1124            hasPublishedEndpoints = _publishedEndpoints.Length > 0;
 1125        }
 126
 1127        if (hasPublishedEndpoints)
 128        {
 129            try
 130            {
 1131                var dummy = new Identity(name: "dummy", "");
 1132                updateLocatorRegistry(locatorInfo, createDirectProxy(dummy));
 1133            }
 0134            catch (LocalException)
 135            {
 136                // If we couldn't update the locator registry, we let the exception go through and don't activate the
 137                // adapter to allow user code to retry activating the adapter later.
 0138                lock (_mutex)
 139                {
 0140                    _state = StateUninitialized;
 0141                    Monitor.PulseAll(_mutex);
 0142                }
 0143                throw;
 144            }
 145        }
 146
 1147        if (printAdapterReady)
 148        {
 1149            Console.Out.WriteLine(_name + " ready");
 150        }
 151
 1152        lock (_mutex)
 153        {
 154            Debug.Assert(_state == StateActivating);
 155
 1156            foreach (IncomingConnectionFactory icf in _incomingConnectionFactories)
 157            {
 1158                icf.activate();
 159            }
 160
 1161            _state = StateActive;
 1162            Monitor.PulseAll(_mutex);
 1163        }
 1164    }
 165
 166    /// <summary>
 167    /// Stops reading requests from incoming connections. Outstanding dispatches are not affected. The object
 168    /// adapter can be reactivated with <see cref="activate"/>.
 169    /// </summary>
 170    /// <remarks>This method is provided for backward compatibility with older versions of Ice. Don't use it in
 171    /// new applications. Holding is not immediate, i.e., after hold returns, the object adapter might still be
 172    /// active for some time. You can use <see cref="waitForHold"/> to wait until holding is complete.</remarks>
 173    public void hold()
 174    {
 1175        lock (_mutex)
 176        {
 1177            checkForDeactivation();
 1178            _state = StateHeld;
 1179            foreach (IncomingConnectionFactory factory in _incomingConnectionFactories)
 180            {
 1181                factory.hold();
 182            }
 183        }
 1184    }
 185
 186    /// <summary>
 187    /// Waits until the object adapter is in the holding state (see <see cref="hold"/>) and the dispatch of requests
 188    /// received over incoming connections has completed.
 189    /// </summary>
 190    /// <remarks>This method is provided for backward compatibility with older versions of Ice. Don't use it in
 191    /// new applications.</remarks>
 192    public void waitForHold()
 193    {
 194        List<IncomingConnectionFactory> incomingConnectionFactories;
 1195        lock (_mutex)
 196        {
 1197            checkForDeactivation();
 1198            incomingConnectionFactories = new List<IncomingConnectionFactory>(_incomingConnectionFactories);
 1199        }
 200
 1201        foreach (IncomingConnectionFactory factory in incomingConnectionFactories)
 202        {
 1203            factory.waitUntilHolding();
 204        }
 1205    }
 206
 207    /// <summary>
 208    /// Deactivates this object adapter: stops accepting new connections from clients and closes gracefully all
 209    /// incoming connections created by this object adapter once all outstanding dispatches have completed. If this
 210    /// object adapter is indirect, this method also unregisters the object adapter from the locator
 211    /// (see <see cref="activate"/>).
 212    /// This method does not cancel outstanding dispatches: it lets them execute until completion.
 213    /// A deactivated object adapter cannot be reactivated again; it can only be destroyed.
 214    /// </summary>
 215    /// <seealso cref="waitForDeactivate"/>
 216    /// <seealso cref="Communicator.shutdown"/>
 217    public void deactivate()
 218    {
 1219        bool hasPublishedEndpoints = false;
 220
 1221        lock (_mutex)
 222        {
 223            // Wait for activation or a previous deactivation to complete.
 224            // This is necessary to avoid out of order locator updates.
 1225            while (_state == StateActivating || _state == StateDeactivating)
 226            {
 0227                Monitor.Wait(_mutex);
 228            }
 1229            if (_state > StateDeactivating)
 230            {
 1231                return;
 232            }
 1233            _state = StateDeactivating;
 234
 1235            hasPublishedEndpoints = _publishedEndpoints.Length > 0;
 1236        }
 237
 238        // The locator infos and incoming connection factory list are immutable at this point.
 239
 1240        if (hasPublishedEndpoints)
 241        {
 242            try
 243            {
 1244                updateLocatorRegistry(_locatorInfo, null);
 1245            }
 1246            catch (LocalException)
 247            {
 248                // We can't throw exceptions in deactivate so we ignore failures to update the locator registry.
 1249            }
 250        }
 251
 1252        foreach (IncomingConnectionFactory factory in _incomingConnectionFactories)
 253        {
 1254            factory.destroy();
 255        }
 256
 1257        lock (_mutex)
 258        {
 259            Debug.Assert(_state == StateDeactivating);
 1260            _state = StateDeactivated;
 1261            Monitor.PulseAll(_mutex);
 1262        }
 1263    }
 264
 265    /// <summary>
 266    /// Waits until <see cref="deactivate"/> is called on this object adapter and all connections accepted by this
 267    /// object adapter are closed. A connection is closed only after all outstanding dispatches on this connection have
 268    /// completed.
 269    /// </summary>
 270    /// <seealso cref="Communicator.waitForShutdown"/>
 271    public void waitForDeactivate()
 272    {
 1273        IncomingConnectionFactory[]? incomingConnectionFactories = null;
 1274        lock (_mutex)
 275        {
 276            // Wait for deactivation of the adapter itself.
 1277            while (_state < StateDeactivated)
 278            {
 1279                Monitor.Wait(_mutex);
 280            }
 1281            if (_state > StateDeactivated)
 282            {
 1283                return;
 284            }
 285
 1286            incomingConnectionFactories = _incomingConnectionFactories.ToArray();
 1287        }
 288
 289        //
 290        // Now we wait for until all incoming connection factories are
 291        // finished.
 292        //
 1293        foreach (IncomingConnectionFactory factory in incomingConnectionFactories)
 294        {
 1295            factory.waitUntilFinished();
 296        }
 1297    }
 298
 299    /// <summary>
 300    /// Checks whether or not <see cref="deactivate"/> was called on this object adapter.
 301    /// </summary>
 302    /// <returns><see langword="true"/> if <see cref="deactivate"/> was called on this object adapter,
 303    /// <see langword="false"/> otherwise.</returns>
 304    public bool isDeactivated()
 305    {
 1306        lock (_mutex)
 307        {
 1308            return _state >= StateDeactivated;
 309        }
 1310    }
 311
 312    /// <summary>
 313    /// Destroys this object adapter and cleans up all resources associated with it. Once this method has
 314    /// returned, you can recreate another object adapter with the same name.
 315    /// </summary>
 316    /// <seealso cref="Communicator.Dispose"/>
 317    public void destroy()
 318    {
 319        //
 320        // Deactivate and wait for completion.
 321        //
 1322        deactivate();
 1323        waitForDeactivate();
 324
 1325        lock (_mutex)
 326        {
 327            //
 328            // Only a single thread is allowed to destroy the object
 329            // adapter. Other threads wait for the destruction to be
 330            // completed.
 331            //
 1332            while (_state == StateDestroying)
 333            {
 0334                Monitor.Wait(_mutex);
 335            }
 1336            if (_state == StateDestroyed)
 337            {
 1338                return;
 339            }
 1340            _state = StateDestroying;
 341
 1342            while (_directCount > 0)
 343            {
 1344                Monitor.Wait(_mutex);
 345            }
 1346        }
 347
 1348        if (_routerInfo is not null)
 349        {
 350            // Remove entry from the router manager.
 1351            _instance.routerManager().erase(_routerInfo.getRouter());
 352
 353            // Clear this object adapter with the router.
 1354            _routerInfo.setAdapter(null);
 355        }
 356
 1357        _instance.outgoingConnectionFactory().removeAdapter(this);
 358
 359        //
 360        // Now it's also time to clean up our servants and servant
 361        // locators.
 362        //
 1363        _servantManager.destroy();
 364
 365        //
 366        // Destroy the thread pool.
 367        //
 1368        if (_threadPool is not null)
 369        {
 1370            _threadPool.destroy();
 1371            _threadPool.joinWithAllThreads();
 372        }
 373
 1374        _objectAdapterFactory?.removeObjectAdapter(this);
 375
 1376        lock (_mutex)
 377        {
 378            //
 379            // We're done, now we can throw away all incoming connection
 380            // factories.
 381            //
 1382            _incomingConnectionFactories.Clear();
 383
 384            //
 385            // Remove object references (some of them cyclic).
 386            //
 1387            _threadPool = null;
 1388            _routerInfo = null;
 1389            _publishedEndpoints = [];
 1390            _locatorInfo = null;
 1391            _reference = null;
 1392            _objectAdapterFactory = null;
 393
 1394            _state = StateDestroyed;
 1395            Monitor.PulseAll(_mutex);
 1396        }
 1397    }
 398
 399    /// <summary>
 400    /// Adds a middleware to the dispatch pipeline of this object adapter.
 401    /// </summary>
 402    /// <param name="middleware">The middleware factory that creates the new middleware when this object adapter
 403    /// creates its dispatch pipeline. A middleware factory is a function that takes an <see cref="Object"/> (the next
 404    /// element in the dispatch pipeline) and returns a new <see cref="Object"/> (the middleware you want to install in
 405    /// the pipeline).</param>
 406    /// <returns>This object adapter.</returns>
 407    /// <remarks>All middleware must be installed before the first dispatch. The middleware are executed in the order
 408    /// they are installed.</remarks>
 409    /// <exception cref="InvalidOperationException">Thrown if the object adapter's dispatch pipeline has already been
 410    /// created. This creation typically occurs the first time the object adapter dispatches an incoming request.
 411    /// </exception>
 412    public ObjectAdapter use(Func<Object, Object> middleware)
 413    {
 1414        if (_dispatchPipeline.IsValueCreated)
 415        {
 0416            throw new InvalidOperationException("All middleware must be installed before the first dispatch.");
 417        }
 1418        _middlewareStack.Push(middleware);
 1419        return this;
 420    }
 421
 422    /// <summary>
 423    /// Adds a servant to this object adapter's Active Servant Map (ASM).
 424    /// The ASM is a map {identity, facet} -> servant.
 425    /// </summary>
 426    /// <param name="servant">The servant to add.</param>
 427    /// <param name="id">The identity of the Ice object that is implemented by the servant.</param>
 428    /// <returns>A proxy that matches the given identity and this object adapter.</returns>
 429    /// <exception cref="AlreadyRegisteredException">Thrown when a servant with the same identity is already
 430    /// registered.</exception>
 431    /// <remarks>This method is equivalent to calling <see cref="addFacet"/> with an empty facet.</remarks>
 1432    public ObjectPrx add(Object servant, Identity id) => addFacet(servant, id, "");
 433
 434    /// <summary>
 435    /// Adds a servant to this object adapter's Active Servant Map (ASM), while specifying a facet.
 436    /// The ASM is a map {identity, facet} -> servant.
 437    /// </summary>
 438    /// <param name="servant">The servant to add.</param>
 439    /// <param name="identity">The identity of the Ice object that is implemented by the servant.</param>
 440    /// <param name="facet">The facet of the Ice object that is implemented by the servant. An empty facet means the
 441    /// default facet.</param>
 442    /// <returns>A proxy that matches the given identity, facet, and this object adapter.</returns>
 443    /// <exception cref="AlreadyRegisteredException">Thrown when a servant with the same identity and facet is already
 444    /// registered.</exception>
 445    public ObjectPrx addFacet(Object servant, Identity identity, string facet)
 446    {
 1447        lock (_mutex)
 448        {
 1449            checkForDestruction();
 1450            checkIdentity(identity);
 1451            ArgumentNullException.ThrowIfNull(servant);
 452
 453            // Create a copy of the Identity argument, in case the caller reuses it.
 1454            var id = new Identity(identity.name, identity.category);
 1455            _servantManager.addServant(servant, id, facet);
 456
 1457            return newProxy(id, facet);
 458        }
 1459    }
 460
 461    /// <summary>
 462    /// Adds a servant to this object adapter's Active Servant Map (ASM), using an automatically generated UUID as its
 463    /// identity.
 464    /// </summary>
 465    /// <param name="servant">The servant to add.</param>
 466    /// <returns>A proxy with the generated UUID identity created by this object adapter.</returns>
 1467    public ObjectPrx addWithUUID(Object servant) => addFacetWithUUID(servant, "");
 468
 469    /// <summary>
 470    /// Adds a servant to this object adapter's Active Servant Map (ASM), using an automatically generated UUID as
 471    /// its identity. Also specifies a facet.
 472    /// </summary>
 473    /// <param name="servant">The servant to add.</param>
 474    /// <param name="facet">The facet of the Ice object that is implemented by the servant. An empty facet means the
 475    /// default facet.</param>
 476    /// <returns>A proxy with the generated UUID identity and the specified facet.</returns>
 477    public ObjectPrx addFacetWithUUID(Object servant, string facet)
 478    {
 1479        var ident = new Identity(Guid.NewGuid().ToString(), "");
 1480        return addFacet(servant, ident, facet);
 481    }
 482
 483    /// <summary>
 484    /// Adds a default servant to handle requests for a specific category. When an object adapter dispatches an
 485    /// incoming request, it tries to find a servant for the identity and facet carried by the request in the
 486    /// following order:
 487    /// <list type="bullet">
 488    /// <item>The object adapter tries to find a servant for the identity and facet in the Active Servant Map.</item>
 489    /// <item>If this fails, the object adapter tries to find a default servant for the category component of the
 490    /// identity.</item>
 491    /// <item>If this fails, the object adapter tries to find a default servant for the empty category, regardless of
 492    /// the category contained in the identity.</item>
 493    /// <item>If this fails, the object adapter tries to find a servant locator for the category component of the
 494    /// identity. If there is no such servant locator, the object adapter tries to find a servant locator for the
 495    /// empty category.
 496    /// <list type="bullet">
 497    /// <item>If a servant locator is found, the object adapter tries to find a servant using this servant locator.
 498    /// </item>
 499    /// </list>
 500    /// </item>
 501    /// <item>If all the previous steps fail, the object adapter gives up and the caller receives an
 502    /// <see cref="ObjectNotExistException"/> or a <see cref="FacetNotExistException"/>.</item>
 503    /// </list>
 504    /// </summary>
 505    /// <param name="servant">The default servant to add.</param>
 506    /// <param name="category">The category for which the default servant is registered. The empty category means it
 507    /// handles all categories.</param>
 508    /// <exception cref="AlreadyRegisteredException">Thrown when a default servant with the same category is already
 509    /// registered.</exception>
 510    public void addDefaultServant(Ice.Object servant, string category)
 511    {
 1512        ArgumentNullException.ThrowIfNull(servant);
 513
 1514        lock (_mutex)
 515        {
 1516            checkForDestruction();
 1517            _servantManager.addDefaultServant(servant, category);
 1518        }
 1519    }
 520
 521    /// <summary>
 522    /// Removes a servant from the object adapter's Active Servant Map.
 523    /// </summary>
 524    /// <param name="id">The identity of the Ice object that is implemented by the servant.</param>
 525    /// <returns>The removed servant.</returns>
 526    /// <exception cref="NotRegisteredException">Thrown when no servant with the given identity is registered.
 527    /// </exception>
 1528    public Object remove(Identity id) => removeFacet(id, "");
 529
 530    /// <summary>
 531    /// Removes a servant from the object adapter's Active Servant Map, while specifying a facet.
 532    /// </summary>
 533    /// <param name="id">The identity of the Ice object that is implemented by the servant.</param>
 534    /// <param name="facet">The facet. An empty facet means the default facet.</param>
 535    /// <returns>The removed servant.</returns>
 536    /// <exception cref="NotRegisteredException">Thrown when no servant with the given identity and facet is
 537    /// registered.</exception>
 538    public Object removeFacet(Identity id, string facet)
 539    {
 1540        lock (_mutex)
 541        {
 1542            checkForDestruction();
 1543            checkIdentity(id);
 544
 1545            return _servantManager.removeServant(id, facet);
 546        }
 1547    }
 548
 549    /// <summary>
 550    /// Removes all facets with the given identity from the Active Servant Map. This method completely removes the
 551    /// Ice object, including its default facet.
 552    /// </summary>
 553    /// <param name="id">The identity of the Ice object to be removed.</param>
 554    /// <returns>A collection containing all the facet names and servants of the removed Ice object.</returns>
 555    /// <exception cref="NotRegisteredException">Thrown when no servant with the given identity is registered.
 556    /// </exception>
 557    public Dictionary<string, Object> removeAllFacets(Identity id)
 558    {
 1559        lock (_mutex)
 560        {
 1561            checkForDestruction();
 1562            checkIdentity(id);
 563
 1564            return _servantManager.removeAllFacets(id);
 565        }
 1566    }
 567
 568    /// <summary>
 569    /// Removes the default servant for a specific category.
 570    /// </summary>
 571    /// <param name="category">The category of the default servant to remove.</param>
 572    /// <returns>The default servant.</returns>
 573    /// <exception cref="NotRegisteredException">Thrown when no default servant is registered for the given category.
 574    /// </exception>
 575    public Object removeDefaultServant(string category)
 576    {
 1577        lock (_mutex)
 578        {
 1579            checkForDestruction();
 1580            return _servantManager.removeDefaultServant(category);
 581        }
 1582    }
 583
 584    /// <summary>
 585    /// Looks up a servant.
 586    /// </summary>
 587    /// <param name="id">The identity of an Ice object.</param>
 588    /// <returns>The servant that implements the Ice object with the given identity, or null if no such servant has
 589    /// been found.</returns>
 590    /// <remarks>This method only tries to find the servant in the ASM and among the default servants. It does not
 591    /// attempt to locate a servant using servant locators.</remarks>
 0592    public Object? find(Identity id) => findFacet(id, "");
 593
 594    /// <summary>
 595    /// Looks up a servant with an identity and facet.
 596    /// </summary>
 597    /// <param name="id">The identity of an Ice object.</param>
 598    /// <param name="facet">The facet of an Ice object. An empty facet means the default facet.</param>
 599    /// <returns>The servant that implements the Ice object with the given identity and facet,
 600    /// or null if no such servant has been found.</returns>
 601    /// <remarks>This method only tries to find the servant in the ASM and among the default servants. It does not
 602    /// attempt to locate a servant using servant locators.</remarks>
 603    public Object? findFacet(Identity id, string facet)
 604    {
 1605        lock (_mutex)
 606        {
 1607            checkForDestruction();
 1608            checkIdentity(id);
 609
 1610            return _servantManager.findServant(id, facet);
 611        }
 1612    }
 613
 614    /// <summary>
 615    /// Finds all facets for a given identity in the Active Servant Map.
 616    /// </summary>
 617    /// <param name="id">The identity.</param>
 618    /// <returns>A collection containing all the facet names and servants that have been found. Can be empty.</returns>
 619    public Dictionary<string, Object> findAllFacets(Identity id)
 620    {
 1621        lock (_mutex)
 622        {
 1623            checkForDestruction();
 1624            checkIdentity(id);
 625
 1626            return _servantManager.findAllFacets(id);
 627        }
 1628    }
 629
 630    /// <summary>
 631    /// Looks up a servant with an identity and a facet. It's equivalent to calling <see cref="findFacet"/>.
 632    /// </summary>
 633    /// <param name="proxy">The proxy that provides the identity and facet to search.</param>
 634    /// <returns>The servant that matches the identity and facet carried by <paramref name="proxy"/>, or null if no
 635    /// such servant has been found.</returns>
 636    /// <remarks>This method only tries to find the servant in the ASM and among the default servants. It does not
 637    /// attempt to locate a servant using servant locators.</remarks>
 638    public Object? findByProxy(ObjectPrx proxy)
 639    {
 0640        lock (_mutex)
 641        {
 0642            checkForDestruction();
 0643            Reference @ref = ((ObjectPrxHelperBase)proxy).iceReference();
 0644            return findFacet(@ref.getIdentity(), @ref.getFacet());
 645        }
 0646    }
 647
 648    /// <summary>
 649    /// Adds a ServantLocator to this object adapter for a specific category.
 650    /// </summary>
 651    /// <param name="locator">The servant locator to add.</param>
 652    /// <param name="category">The category. The empty category means <paramref name="locator"/> handles all
 653    /// categories.</param>
 654    /// <exception cref="AlreadyRegisteredException">Thrown when a servant locator with the same category is already
 655    /// registered.</exception>
 656    /// <seealso cref="addDefaultServant"/>
 657    public void addServantLocator(ServantLocator locator, string category)
 658    {
 1659        lock (_mutex)
 660        {
 1661            checkForDestruction();
 1662            _servantManager.addServantLocator(locator, category);
 1663        }
 1664    }
 665
 666    /// <summary>
 667    /// Removes a ServantLocator from this object adapter.
 668    /// </summary>
 669    /// <param name="category">The category.</param>
 670    /// <returns>The servant locator.</returns>
 671    /// <exception cref="NotRegisteredException">Thrown when no servant locator with the given category is registered.
 672    /// </exception>
 673    public ServantLocator removeServantLocator(string category)
 674    {
 1675        lock (_mutex)
 676        {
 1677            checkForDestruction();
 1678            return _servantManager.removeServantLocator(category);
 679        }
 1680    }
 681
 682    /// <summary>
 683    /// Finds a ServantLocator registered with this object adapter.
 684    /// </summary>
 685    /// <param name="category">The category.</param>
 686    /// <returns>The servant locator, or null if not found.</returns>
 687    public ServantLocator? findServantLocator(string category)
 688    {
 0689        lock (_mutex)
 690        {
 0691            checkForDestruction();
 0692            return _servantManager.findServantLocator(category);
 693        }
 0694    }
 695
 696    /// <summary>
 697    /// Finds the default servant for a specific category.
 698    /// </summary>
 699    /// <param name="category">The category.</param>
 700    /// <returns>The default servant, or nullptr if not found.</returns>
 701    public Object? findDefaultServant(string category)
 702    {
 1703        lock (_mutex)
 704        {
 1705            checkForDestruction();
 1706            return _servantManager.findDefaultServant(category);
 707        }
 1708    }
 709
 710    /// <summary>
 711    /// Gets the dispatch pipeline of this object adapter.
 712    /// </summary>
 713    /// <value>The dispatch pipeline.</value>
 1714    public Object dispatchPipeline => _dispatchPipeline.Value;
 715
 716    /// <summary>
 717    /// Creates a proxy from an Ice identity.
 718    /// If this object adapter is configured with an adapter ID, the proxy is an indirect proxy that refers to this
 719    /// adapter ID. If a replica group ID is also defined, the proxy is an indirect proxy that refers to this replica
 720    /// group ID. Otherwise, the proxy is a direct proxy containing this object adapter's published endpoints.
 721    /// </summary>
 722    /// <param name="id">An Ice identity.</param>
 723    /// <returns>A proxy with the given identity.</returns>
 724    public ObjectPrx createProxy(Identity id)
 725    {
 1726        lock (_mutex)
 727        {
 1728            checkForDestruction();
 1729            checkIdentity(id);
 730
 1731            return newProxy(id, "");
 732        }
 1733    }
 734
 735    /// <summary>
 736    /// Creates a direct proxy from an Ice identity.
 737    /// </summary>
 738    /// <param name="id">An Ice identity.</param>
 739    /// <returns>A proxy with the given identity and the published endpoints of this object adapter.</returns>
 740    public ObjectPrx createDirectProxy(Identity id)
 741    {
 1742        lock (_mutex)
 743        {
 1744            checkForDestruction();
 1745            checkIdentity(id);
 746
 1747            return newDirectProxy(id, "");
 748        }
 1749    }
 750
 751    /// <summary>
 752    /// Creates an indirect proxy for an Ice identity.
 753    /// </summary>
 754    /// <param name="id">An Ice identity.</param>
 755    /// <returns>An indirect proxy with the given identity. If this object adapter is not configured with an adapter
 756    /// ID or a replica group ID, the new proxy is a well-known proxy (i.e., an identity-only proxy).</returns>
 757    public ObjectPrx createIndirectProxy(Identity id)
 758    {
 1759        lock (_mutex)
 760        {
 1761            checkForDestruction();
 1762            checkIdentity(id);
 763
 1764            return newIndirectProxy(id, "", _id);
 765        }
 1766    }
 767
 768    /// <summary>
 769    /// Sets an Ice locator on this object adapter.
 770    /// </summary>
 771    /// <param name="locator">The locator used by this object adapter.</param>
 772    public void setLocator(LocatorPrx? locator)
 773    {
 1774        lock (_mutex)
 775        {
 1776            checkForDeactivation();
 1777            _locatorInfo = _instance.locatorManager().get(locator);
 1778        }
 1779    }
 780
 781    /// <summary>
 782    /// Gets the Ice locator used by this object adapter.
 783    /// </summary>
 784    /// <returns>The locator used by this object adapter, or null if no locator is used by this object adapter.
 785    /// </returns>
 786    public LocatorPrx? getLocator()
 787    {
 1788        lock (_mutex)
 789        {
 1790            return _locatorInfo?.getLocator();
 791        }
 1792    }
 793
 794    /// <summary>
 795    /// Gets the set of endpoints configured on this object adapter.
 796    /// </summary>
 797    /// <returns>The set of endpoints.</returns>
 798    /// <remarks>This method remains usable after the object adapter has been deactivated.</remarks>
 799    public Endpoint[] getEndpoints()
 800    {
 1801        lock (_mutex)
 802        {
 1803            var endpoints = new List<Endpoint>();
 1804            foreach (IncomingConnectionFactory factory in _incomingConnectionFactories)
 805            {
 1806                endpoints.Add(factory.endpoint());
 807            }
 1808            return endpoints.ToArray();
 809        }
 1810    }
 811
 812    /// <summary>
 813    /// Gets the set of endpoints that proxies created by this object adapter will contain.
 814    /// </summary>
 815    /// <returns>The set of published endpoints.</returns>
 816    /// <remarks>This method remains usable after the object adapter has been deactivated.</remarks>
 817    public Endpoint[] getPublishedEndpoints()
 818    {
 1819        lock (_mutex)
 820        {
 1821            return (Endpoint[])_publishedEndpoints.Clone();
 822        }
 1823    }
 824
 825    /// <summary>
 826    /// Sets the endpoints that proxies created by this object adapter will contain.
 827    /// </summary>
 828    /// <param name="newEndpoints">The new set of endpoints that the object adapter will embed in proxies.</param>
 829    /// <exception cref="ArgumentException">Thrown when <paramref name="newEndpoints"/> is empty or this adapter is
 830    /// associated with a router.</exception>
 831    public void setPublishedEndpoints(Endpoint[] newEndpoints)
 832    {
 1833        if (newEndpoints.Length == 0)
 834        {
 0835            throw new ArgumentException(
 0836                $"The {nameof(newEndpoints)} argument must contain at least one endpoint.", nameof(newEndpoints));
 837        }
 838
 1839        LocatorInfo? locatorInfo = null;
 840        EndpointI[] oldPublishedEndpoints;
 841
 1842        lock (_mutex)
 843        {
 1844            checkForDeactivation();
 845
 1846            if (_routerInfo is not null)
 847            {
 1848                throw new ArgumentException(
 1849                    "Cannot set published endpoints on an object adapter associated with a router.");
 850            }
 851
 1852            oldPublishedEndpoints = _publishedEndpoints;
 1853            _publishedEndpoints = Array.ConvertAll(newEndpoints, endpt => (EndpointI)endpt);
 1854            locatorInfo = _locatorInfo;
 1855        }
 856
 857        try
 858        {
 1859            var dummy = new Identity("dummy", "");
 1860            updateLocatorRegistry(locatorInfo, createDirectProxy(dummy));
 1861        }
 0862        catch (LocalException)
 863        {
 0864            lock (_mutex)
 865            {
 866                // Restore the old published endpoints.
 0867                _publishedEndpoints = oldPublishedEndpoints;
 0868                throw;
 869            }
 870        }
 1871    }
 872
 873    internal bool isLocal(Reference r)
 874    {
 875        //
 876        // NOTE: it's important that isLocal() doesn't perform any blocking operations as
 877        // it can be called for AMI invocations if the proxy has no delegate set yet.
 878        //
 879
 1880        if (r.isWellKnown())
 881        {
 882            // Check the active servant map to see if the well-known
 883            // proxy is for a local object.
 1884            return _servantManager.hasServant(r.getIdentity());
 885        }
 1886        else if (r.isIndirect())
 887        {
 888            // Proxy is local if the reference adapter id matches this
 889            // adapter id or replica group id.
 1890            return r.getAdapterId().Equals(_id, StringComparison.Ordinal) ||
 1891                r.getAdapterId().Equals(_replicaGroupId, StringComparison.Ordinal);
 892        }
 893        else
 894        {
 895            // Proxies which have at least one endpoint in common with the published endpoints are considered local.
 896            // This check doesn't take datagram endpoints into account; this effectively disables colloc optimization
 897            // for UDP.
 1898            lock (_mutex)
 899            {
 1900                checkForDestruction();
 1901                IEnumerable<EndpointI> endpoints = r.getEndpoints().Where(e => !e.datagram());
 1902                return _publishedEndpoints.Any(e => endpoints.Any(e.equivalent));
 903            }
 904        }
 1905    }
 906
 907    internal void flushAsyncBatchRequests(Ice.CompressBatch compressBatch, CommunicatorFlushBatchAsync outAsync)
 908    {
 909        List<IncomingConnectionFactory> f;
 1910        lock (_mutex)
 911        {
 1912            f = new List<IncomingConnectionFactory>(_incomingConnectionFactories);
 1913        }
 914
 1915        foreach (IncomingConnectionFactory factory in f)
 916        {
 1917            factory.flushAsyncBatchRequests(compressBatch, outAsync);
 918        }
 1919    }
 920
 921    internal void updateConnectionObservers()
 922    {
 923        List<IncomingConnectionFactory> f;
 1924        lock (_mutex)
 925        {
 1926            f = new List<IncomingConnectionFactory>(_incomingConnectionFactories);
 1927        }
 928
 1929        foreach (IncomingConnectionFactory p in f)
 930        {
 1931            p.updateConnectionObservers();
 932        }
 1933    }
 934
 935    internal void updateThreadObservers()
 936    {
 937        Ice.Internal.ThreadPool? threadPool;
 1938        lock (_mutex)
 939        {
 1940            threadPool = _threadPool;
 1941        }
 942
 1943        threadPool?.updateObservers();
 1944    }
 945
 946    internal void incDirectCount()
 947    {
 1948        lock (_mutex)
 949        {
 1950            checkForDestruction();
 951
 952            Debug.Assert(_directCount >= 0);
 1953            ++_directCount;
 1954        }
 1955    }
 956
 957    internal void decDirectCount()
 958    {
 1959        lock (_mutex)
 960        {
 961            // Not check for destruction here!
 962
 963            Debug.Assert(_instance is not null); // destroy waits for _directCount to reach 0
 964
 965            Debug.Assert(_directCount > 0);
 1966            if (--_directCount == 0)
 967            {
 1968                Monitor.PulseAll(_mutex);
 969            }
 1970        }
 1971    }
 972
 973    internal Ice.Internal.ThreadPool getThreadPool()
 974    {
 975        // No mutex lock necessary, _threadPool and _instance are
 976        // immutable after creation until they are removed in destroy().
 977
 978        // Not check for deactivation here!
 979
 980        Debug.Assert(_instance is not null); // Must not be called after destroy().
 981
 1982        if (_threadPool is not null)
 983        {
 1984            return _threadPool;
 985        }
 986        else
 987        {
 1988            return _instance.serverThreadPool();
 989        }
 990    }
 991
 992    internal void setAdapterOnConnection(Ice.ConnectionI connection)
 993    {
 1994        lock (_mutex)
 995        {
 1996            checkForDestruction();
 1997            connection.setAdapterFromAdapter(this);
 1998        }
 1999    }
 1000
 11001    internal int messageSizeMax() => _messageSizeMax;
 1002
 1003    //
 1004    // Only for use by ObjectAdapterFactory
 1005    //
 11006    internal ObjectAdapter(
 11007        Instance instance,
 11008        Communicator communicator,
 11009        ObjectAdapterFactory objectAdapterFactory,
 11010        string name,
 11011        RouterPrx? router,
 11012        bool noConfig,
 11013        SslServerAuthenticationOptions? serverAuthenticationOptions)
 1014    {
 11015        _instance = instance;
 11016        _communicator = communicator;
 11017        _objectAdapterFactory = objectAdapterFactory;
 11018        _servantManager = new ServantManager(instance, name);
 1019
 11020        _dispatchPipeline = new Lazy<Object>(createDispatchPipeline);
 11021        _name = name;
 11022        _incomingConnectionFactories = [];
 11023        _publishedEndpoints = [];
 11024        _routerInfo = null;
 11025        _directCount = 0;
 11026        _noConfig = noConfig;
 11027        _serverAuthenticationOptions = serverAuthenticationOptions;
 1028
 1029        // Install default middleware depending on the communicator's configuration.
 11030        if (_instance.initializationData().logger is Logger logger)
 1031        {
 11032            int warningLevel = _instance.initializationData().properties!.getIcePropertyAsInt("Ice.Warn.Dispatch");
 11033            if (_instance.traceLevels().dispatch > 0 || warningLevel > 0)
 1034            {
 11035                use(next =>
 11036                    new LoggerMiddleware(
 11037                        next,
 11038                        logger,
 11039                        _instance.traceLevels().dispatch,
 11040                        _instance.traceLevels().dispatchCat,
 11041                        warningLevel,
 11042                        _instance.toStringMode()));
 1043            }
 1044        }
 11045        if (_instance.initializationData().observer is CommunicatorObserver observer)
 1046        {
 11047            use(next => new ObserverMiddleware(next, observer));
 1048        }
 1049
 11050        if (_noConfig)
 1051        {
 11052            _id = "";
 11053            _replicaGroupId = "";
 11054            _reference = _instance.referenceFactory().create("dummy -t", "");
 11055            return;
 1056        }
 1057
 11058        Properties properties = _instance.initializationData().properties!;
 11059        Properties.validatePropertiesWithPrefix(_name, properties, PropertyNames.ObjectAdapterProps);
 1060
 1061        // Make sure named adapter has configuration.
 11062        if (router is null && properties.getPropertiesForPrefix($"{_name}.").Count == 0)
 1063        {
 1064            // These need to be set to prevent warnings/asserts in the destructor.
 11065            _state = StateDestroyed;
 11066            _incomingConnectionFactories = [];
 1067
 11068            throw new InitializationException($"Object adapter '{name}' requires configuration.");
 1069        }
 1070
 11071        _id = properties.getProperty(_name + ".AdapterId");
 11072        _replicaGroupId = properties.getProperty(_name + ".ReplicaGroupId");
 1073
 1074        // Setup a reference to be used to get the default proxy options
 1075        // when creating new proxies. By default, create twoway proxies.
 11076        string proxyOptions = properties.getPropertyWithDefault(_name + ".ProxyOptions", "-t");
 1077        try
 1078        {
 11079            _reference = _instance.referenceFactory().create("dummy " + proxyOptions, "");
 11080        }
 01081        catch (ParseException ex)
 1082        {
 01083            throw new InitializationException(
 01084                $"Invalid proxy options '{proxyOptions}' for object adapter '{_name}'.",
 01085                ex);
 1086        }
 1087
 1088        // The maximum size of an Ice protocol message in bytes. This is limited to 0x7fffffff, which corresponds to
 1089        // the maximum value of a 32-bit signed integer (int).
 1090        const int messageSizeMaxUpperLimit = int.MaxValue;
 11091        int defaultMessageSizeMax = instance.messageSizeMax() / 1024;
 11092        int messageSizeMax = properties.getPropertyAsIntWithDefault($"{_name}.MessageSizeMax", defaultMessageSizeMax);
 11093        if (messageSizeMax > messageSizeMaxUpperLimit / 1024)
 1094        {
 01095            throw new Ice.InitializationException(
 01096                $"{_name}.MessageSizeMax '{messageSizeMax}' is too large, it must be less than or equal to '{messageSize
 1097        }
 11098        else if (messageSizeMax < 1)
 1099        {
 11100            _messageSizeMax = messageSizeMaxUpperLimit;
 1101        }
 1102        else
 1103        {
 1104            // The property is specified in kibibytes (KiB); _messageSizeMax is stored in bytes.
 11105            _messageSizeMax = messageSizeMax * 1024;
 1106        }
 1107
 1108        try
 1109        {
 1110            // If the user configured any of the ObjectAdapter.ThreadPool properties, create a per-adapter thread pool.
 1111            // Otherwise the OA will use the default server thread pool.
 11112            if (properties.getPropertiesForPrefix(_name + ".ThreadPool.").Count > 0)
 1113            {
 11114                _threadPool = new Ice.Internal.ThreadPool(_instance, _name + ".ThreadPool", 0);
 1115            }
 1116
 11117            router ??= RouterPrxHelper.uncheckedCast(communicator.propertyToProxy(_name + ".Router"));
 11118            if (router is not null)
 1119            {
 11120                _routerInfo = _instance.routerManager().get(router);
 1121                Debug.Assert(_routerInfo is not null);
 1122
 11123                if (properties.getProperty($"{_name}.Endpoints").Length > 0)
 1124                {
 11125                    throw new InitializationException(
 11126                        "An object adapter with a router cannot accept incoming connections.");
 1127                }
 1128
 1129                // Make sure this router is not already registered with another adapter.
 11130                if (_routerInfo.getAdapter() is not null)
 1131                {
 01132                    throw new AlreadyRegisteredException(
 01133                        "object adapter with router",
 01134                        Util.identityToString(router.ice_getIdentity(), _instance.toStringMode()));
 1135                }
 1136
 1137                // Associate this object adapter with the router. This way,
 1138                // new outgoing connections to the router's client proxy will
 1139                // use this object adapter for callbacks.
 11140                _routerInfo.setAdapter(this);
 1141
 1142                // Also modify all existing outgoing connections to the
 1143                // router's client proxy to use this object adapter for callbacks.
 11144                _instance.outgoingConnectionFactory().setRouterInfo(_routerInfo);
 1145            }
 1146            else
 1147            {
 1148                // Parse the endpoints, but don't store them in the adapter. The connection
 1149                // factory might change it, for example, to fill in the real port number.
 11150                List<EndpointI> endpoints = parseEndpoints(properties.getProperty(_name + ".Endpoints"), true);
 11151                foreach (EndpointI endp in endpoints)
 1152                {
 11153                    foreach (EndpointI expanded in endp.expandHost())
 1154                    {
 11155                        var factory = new IncomingConnectionFactory(instance, expanded, this);
 11156                        _incomingConnectionFactories.Add(factory);
 1157                    }
 1158                }
 11159                if (endpoints.Count == 0)
 1160                {
 11161                    TraceLevels tl = _instance.traceLevels();
 11162                    if (tl.network >= 2)
 1163                    {
 11164                        _instance.initializationData().logger!.trace(
 11165                            tl.networkCat,
 11166                            $"created adapter '{_name}' without endpoints");
 1167                    }
 1168                }
 1169            }
 1170
 1171            // Parse published endpoints.
 11172            _publishedEndpoints = computePublishedEndpoints();
 1173
 11174            if (properties.getProperty(_name + ".Locator").Length > 0)
 1175            {
 01176                setLocator(LocatorPrxHelper.uncheckedCast(communicator.propertyToProxy(_name + ".Locator")));
 1177            }
 1178            else
 1179            {
 11180                setLocator(_instance.referenceFactory().getDefaultLocator());
 1181            }
 11182        }
 11183        catch (LocalException)
 1184        {
 11185            destroy();
 11186            throw;
 1187        }
 11188    }
 1189
 1190    internal static void checkIdentity(Identity ident)
 1191    {
 11192        if (ident.name.Length == 0)
 1193        {
 11194            throw new ArgumentException("The name of an Ice object identity cannot be empty.", nameof(ident));
 1195        }
 11196    }
 1197
 11198    internal SslServerAuthenticationOptions? getServerAuthenticationOptions() => _serverAuthenticationOptions;
 1199
 1200    private ObjectPrx newProxy(Identity ident, string facet)
 1201    {
 11202        if (_id.Length == 0)
 1203        {
 11204            return newDirectProxy(ident, facet);
 1205        }
 11206        else if (_replicaGroupId.Length == 0)
 1207        {
 11208            return newIndirectProxy(ident, facet, _id);
 1209        }
 1210        else
 1211        {
 11212            return newIndirectProxy(ident, facet, _replicaGroupId);
 1213        }
 1214    }
 1215
 1216    private ObjectPrx newDirectProxy(Identity ident, string facet) =>
 11217        new ObjectPrxHelper(_instance.referenceFactory().create(ident, facet, _reference, _publishedEndpoints));
 1218
 1219    private ObjectPrx newIndirectProxy(Identity ident, string facet, string id) =>
 11220        new ObjectPrxHelper(_instance.referenceFactory().create(ident, facet, _reference, id));
 1221
 1222    private void checkForDeactivation()
 1223    {
 11224        checkForDestruction();
 1225
 11226        if (_state >= StateDeactivating)
 1227        {
 01228            throw new ObjectAdapterDeactivatedException(getName());
 1229        }
 11230    }
 1231
 1232    private void checkForDestruction()
 1233    {
 11234        if (_state >= StateDestroying)
 1235        {
 11236            throw new ObjectAdapterDestroyedException(getName());
 1237        }
 11238    }
 1239
 1240    private List<EndpointI> parseEndpoints(string endpts, bool oaEndpoints)
 1241    {
 1242        int beg;
 11243        int end = 0;
 1244
 11245        string delim = " \t\n\r";
 1246
 11247        var endpoints = new List<EndpointI>();
 11248        while (end < endpts.Length)
 1249        {
 11250            beg = Ice.UtilInternal.StringUtil.findFirstNotOf(endpts, delim, end);
 11251            if (beg == -1)
 1252            {
 11253                if (endpoints.Count != 0)
 1254                {
 11255                    throw new ParseException("invalid empty object adapter endpoint");
 1256                }
 1257                break;
 1258            }
 1259
 11260            end = beg;
 11261            while (true)
 1262            {
 11263                end = endpts.IndexOf(':', end);
 11264                if (end == -1)
 1265                {
 11266                    end = endpts.Length;
 11267                    break;
 1268                }
 1269                else
 1270                {
 11271                    bool quoted = false;
 11272                    int quote = beg;
 11273                    while (true)
 1274                    {
 11275                        quote = endpts.IndexOf('\"', quote);
 11276                        if (quote == -1 || end < quote)
 1277                        {
 1278                            break;
 1279                        }
 1280                        else
 1281                        {
 11282                            quote = endpts.IndexOf('\"', ++quote);
 11283                            if (quote == -1)
 1284                            {
 1285                                break;
 1286                            }
 11287                            else if (end < quote)
 1288                            {
 11289                                quoted = true;
 11290                                break;
 1291                            }
 11292                            ++quote;
 1293                        }
 1294                    }
 11295                    if (!quoted)
 1296                    {
 1297                        break;
 1298                    }
 11299                    ++end;
 1300                }
 1301            }
 1302
 11303            if (end == beg)
 1304            {
 11305                throw new ParseException("invalid empty object adapter endpoint");
 1306            }
 1307
 11308            string s = endpts[beg..end];
 11309            EndpointI endp = _instance.endpointFactoryManager().create(s, oaEndpoints) ??
 11310                throw new ParseException($"invalid object adapter endpoint '{s}'");
 11311            endpoints.Add(endp);
 1312
 11313            ++end;
 1314        }
 1315
 11316        return endpoints;
 1317    }
 1318
 1319    private EndpointI[] computePublishedEndpoints()
 1320    {
 1321        IEnumerable<EndpointI> endpoints;
 11322        if (_routerInfo is not null)
 1323        {
 1324            // Get the router's server proxy endpoints and use them as the published endpoints.
 11325            endpoints = _routerInfo.getServerEndpoints();
 1326        }
 1327        else
 1328        {
 1329            // Parse published endpoints. If set, these are used instead of the connection factory endpoints.
 11330            endpoints = parseEndpoints(
 11331                _instance.initializationData().properties!.getProperty($"{_name}.PublishedEndpoints"),
 11332                oaEndpoints: false);
 1333
 11334            if (!endpoints.Any())
 1335            {
 1336                // If the PublishedEndpoints property isn't set, we compute the published endpoints from the factory
 1337                // endpoints.
 11338                endpoints = _incomingConnectionFactories.Select(f => f.endpoint());
 1339
 1340                // Remove all loopback/multicast endpoints.
 11341                IEnumerable<EndpointI> endpointsNoLoopback = endpoints.Where(e => !e.isLoopbackOrMulticast());
 1342
 1343                // Retrieve published host
 11344                string publishedHost = _instance.initializationData().properties!.getProperty($"{_name}.PublishedHost");
 1345
 11346                if (endpointsNoLoopback.Any())
 1347                {
 11348                    endpoints = endpointsNoLoopback;
 1349
 1350                    // For non-loopback & non-multicast endpoints, we use the fully qualified name of the local host as
 1351                    // default for publishedHost.
 11352                    if (publishedHost.Length == 0)
 1353                    {
 11354                        publishedHost = Dns.GetHostEntry("").HostName; // fully qualified name of local host
 1355                    }
 1356                }
 1357
 1358                // Replace the host in all endpoints by publishedHost (when applicable) and clear all local options.
 11359                endpoints = endpoints.Select(e => e.toPublishedEndpoint(publishedHost)).Distinct();
 1360            }
 1361        }
 1362
 11363        EndpointI[] endpointsArray = endpoints.ToArray();
 1364
 11365        if (_instance.traceLevels().network >= 1 && endpointsArray.Length > 0)
 1366        {
 11367            var s = new StringBuilder("published endpoints for object adapter '");
 11368            s.Append(_name);
 11369            s.Append("':\n");
 11370            bool first = true;
 11371            foreach (EndpointI endpoint in endpointsArray)
 1372            {
 11373                if (!first)
 1374                {
 01375                    s.Append(':');
 1376                }
 11377                s.Append(endpoint.ToString());
 11378                first = false;
 1379            }
 11380            _instance.initializationData().logger!.trace(_instance.traceLevels().networkCat, s.ToString());
 1381        }
 1382
 11383        return endpointsArray;
 1384    }
 1385
 1386    private void updateLocatorRegistry(LocatorInfo? locatorInfo, ObjectPrx? proxy)
 1387    {
 11388        if (_id.Length == 0 || locatorInfo is null)
 1389        {
 11390            return; // Nothing to update.
 1391        }
 1392
 1393        // Call on the locator registry outside the synchronization to
 1394        // blocking other threads that need to lock this OA.
 11395        LocatorRegistryPrx locatorRegistry = locatorInfo.getLocatorRegistry();
 11396        if (locatorRegistry is null)
 1397        {
 11398            return;
 1399        }
 1400
 1401        try
 1402        {
 11403            if (_replicaGroupId.Length == 0)
 1404            {
 11405                locatorRegistry.setAdapterDirectProxy(_id, proxy);
 1406            }
 1407            else
 1408            {
 11409                locatorRegistry.setReplicatedAdapterDirectProxy(_id, _replicaGroupId, proxy);
 1410            }
 11411        }
 01412        catch (AdapterNotFoundException)
 1413        {
 01414            if (_instance!.traceLevels().location >= 1)
 1415            {
 01416                var s = new StringBuilder();
 01417                s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
 01418                s.Append("the object adapter is not known to the locator registry");
 01419                _instance.initializationData().logger!.trace(_instance.traceLevels().locationCat, s.ToString());
 1420            }
 1421
 01422            throw new NotRegisteredException("object adapter", _id);
 1423        }
 01424        catch (InvalidReplicaGroupIdException)
 1425        {
 01426            if (_instance.traceLevels().location >= 1)
 1427            {
 01428                var s = new StringBuilder();
 01429                s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
 01430                s.Append("the replica group `" + _replicaGroupId + "' is not known to the locator registry");
 01431                _instance.initializationData().logger!.trace(_instance.traceLevels().locationCat, s.ToString());
 1432            }
 1433
 01434            throw new NotRegisteredException("replica group", _replicaGroupId);
 1435        }
 01436        catch (AdapterAlreadyActiveException)
 1437        {
 01438            if (_instance.traceLevels().location >= 1)
 1439            {
 01440                var s = new StringBuilder();
 01441                s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
 01442                s.Append("the object adapter endpoints are already set");
 01443                _instance.initializationData().logger!.trace(_instance.traceLevels().locationCat, s.ToString());
 1444            }
 1445
 01446            throw new ObjectAdapterIdInUseException(_id);
 1447        }
 01448        catch (ObjectAdapterDeactivatedException)
 1449        {
 1450            // Expected if collocated call and OA is deactivated, ignore.
 01451        }
 01452        catch (ObjectAdapterDestroyedException)
 1453        {
 1454            // Ignore
 01455        }
 01456        catch (CommunicatorDestroyedException)
 1457        {
 1458            // Ignore
 01459        }
 11460        catch (LocalException e)
 1461        {
 11462            if (_instance.traceLevels().location >= 1)
 1463            {
 11464                var s = new StringBuilder();
 11465                s.Append("couldn't update object adapter `" + _id + "' endpoints with the locator registry:\n");
 11466                s.Append(e.ToString());
 11467                _instance.initializationData().logger!.trace(_instance.traceLevels().locationCat, s.ToString());
 1468            }
 11469            throw; // TODO: Shall we raise a special exception instead of a non obvious local exception?
 1470        }
 1471
 11472        if (_instance.traceLevels().location >= 1)
 1473        {
 11474            var s = new StringBuilder();
 11475            s.Append("updated object adapter `" + _id + "' endpoints with the locator registry\n");
 11476            s.Append("endpoints = ");
 11477            if (proxy is not null)
 1478            {
 11479                Endpoint[] endpoints = proxy.ice_getEndpoints();
 11480                for (int i = 0; i < endpoints.Length; i++)
 1481                {
 11482                    s.Append(endpoints[i].ToString());
 11483                    if (i + 1 < endpoints.Length)
 1484                    {
 01485                        s.Append(':');
 1486                    }
 1487                }
 1488            }
 11489            _instance.initializationData().logger!.trace(_instance.traceLevels().locationCat, s.ToString());
 1490        }
 11491    }
 1492
 1493    private Object createDispatchPipeline()
 1494    {
 11495        Object dispatchPipeline = _servantManager; // the "final" dispatcher
 11496        foreach (Func<Object, Object> middleware in _middlewareStack)
 1497        {
 11498            dispatchPipeline = middleware(dispatchPipeline);
 1499        }
 11500        _middlewareStack.Clear(); // we no longer need these functions
 11501        return dispatchPipeline;
 1502    }
 1503}

Methods/Properties

.ctor(Ice.Internal.Instance, Ice.Communicator, Ice.Internal.ObjectAdapterFactory, string, Ice.RouterPrx, bool, System.Net.Security.SslServerAuthenticationOptions)
getName()
getCommunicator()
activate()
hold()
waitForHold()
deactivate()
waitForDeactivate()
isDeactivated()
destroy()
use(System.Func<Ice.Object, Ice.Object>)
add(Ice.Object, Ice.Identity)
addFacet(Ice.Object, Ice.Identity, string)
addWithUUID(Ice.Object)
addFacetWithUUID(Ice.Object, string)
addDefaultServant(Ice.Object, string)
remove(Ice.Identity)
removeFacet(Ice.Identity, string)
removeAllFacets(Ice.Identity)
removeDefaultServant(string)
find(Ice.Identity)
findFacet(Ice.Identity, string)
findAllFacets(Ice.Identity)
findByProxy(Ice.ObjectPrx)
addServantLocator(Ice.ServantLocator, string)
removeServantLocator(string)
findServantLocator(string)
findDefaultServant(string)
get_dispatchPipeline()
createProxy(Ice.Identity)
createDirectProxy(Ice.Identity)
createIndirectProxy(Ice.Identity)
setLocator(Ice.LocatorPrx)
getLocator()
getEndpoints()
getPublishedEndpoints()
setPublishedEndpoints(Ice.Endpoint[])
isLocal(Ice.Internal.Reference)
flushAsyncBatchRequests(Ice.CompressBatch, Ice.Internal.CommunicatorFlushBatchAsync)
updateConnectionObservers()
updateThreadObservers()
incDirectCount()
decDirectCount()
getThreadPool()
setAdapterOnConnection(Ice.ConnectionI)
messageSizeMax()
checkIdentity(Ice.Identity)
getServerAuthenticationOptions()
newProxy(Ice.Identity, string)
newDirectProxy(Ice.Identity, string)
newIndirectProxy(Ice.Identity, string, string)
checkForDeactivation()
checkForDestruction()
parseEndpoints(string, bool)
computePublishedEndpoints()
updateLocatorRegistry(Ice.Internal.LocatorInfo, Ice.ObjectPrx)
createDispatchPipeline()