1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 using System.Collections;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Threading;
9 
10 namespace IceInternal
11 {
12     public sealed class LocatorInfo
13     {
14         public interface GetEndpointsCallback
15         {
setEndpoints(EndpointI[] endpoints, bool cached)16             void setEndpoints(EndpointI[] endpoints, bool cached);
setException(Ice.LocalException ex)17             void setException(Ice.LocalException ex);
18         }
19 
20         private class RequestCallback
21         {
22             public void
response(LocatorInfo locatorInfo, Ice.ObjectPrx proxy)23             response(LocatorInfo locatorInfo, Ice.ObjectPrx proxy)
24             {
25                 EndpointI[] endpoints = null;
26                 if(proxy != null)
27                 {
28                     Reference r = ((Ice.ObjectPrxHelperBase)proxy).iceReference();
29                     if(_ref.isWellKnown() && !Protocol.isSupported(_ref.getEncoding(), r.getEncoding()))
30                     {
31                         //
32                         // If a well-known proxy and the returned
33                         // proxy encoding isn't supported, we're done:
34                         // there's no compatible endpoint we can use.
35                         //
36                     }
37                     else if(!r.isIndirect())
38                     {
39                         endpoints = r.getEndpoints();
40                     }
41                     else if(_ref.isWellKnown() && !r.isWellKnown())
42                     {
43                         //
44                         // We're resolving the endpoints of a well-known object and the proxy returned
45                         // by the locator is an indirect proxy. We now need to resolve the endpoints
46                         // of this indirect proxy.
47                         //
48                         if(_ref.getInstance().traceLevels().location >= 1)
49                         {
50                             locatorInfo.trace("retrieved adapter for well-known object from locator, " +
51                                               "adding to locator cache", _ref, r);
52                         }
53                         locatorInfo.getEndpoints(r, _ref, _ttl, _callback);
54                         return;
55                     }
56                 }
57 
58                 if(_ref.getInstance().traceLevels().location >= 1)
59                 {
60                     locatorInfo.getEndpointsTrace(_ref, endpoints, false);
61                 }
62                 if(_callback != null)
63                 {
64                     _callback.setEndpoints(endpoints == null ? new EndpointI[0] : endpoints, false);
65                 }
66             }
67 
68             public void
exception(LocatorInfo locatorInfo, Ice.Exception exc)69             exception(LocatorInfo locatorInfo, Ice.Exception exc)
70             {
71                 try
72                 {
73                     locatorInfo.getEndpointsException(_ref, exc); // This throws.
74                 }
75                 catch(Ice.LocalException ex)
76                 {
77                     if(_callback != null)
78                     {
79                         _callback.setException(ex);
80                     }
81                 }
82             }
83 
84             public
85             RequestCallback(Reference @ref, int ttl, GetEndpointsCallback cb)
86             {
87                 _ref = @ref;
88                 _ttl = ttl;
89                 _callback = cb;
90             }
91 
92             readonly Reference _ref;
93             readonly int _ttl;
94             readonly GetEndpointsCallback _callback;
95         }
96 
97         private abstract class Request
98         {
99             public void
100             addCallback(Reference @ref, Reference wellKnownRef, int ttl, GetEndpointsCallback cb)
101             {
102                 RequestCallback callback = new RequestCallback(@ref, ttl, cb);
103                 lock(this)
104                 {
105                     if(!_response && _exception == null)
106                     {
107                         _callbacks.Add(callback);
108                         if(wellKnownRef != null)
109                         {
110                             // This request is to resolve the endpoints of a cached well-known object ref
111                             _wellKnownRefs.Add(wellKnownRef);
112                         }
113                         if(!_sent)
114                         {
115                             _sent = true;
116                             send();
117                         }
118                         return;
119                     }
120                 }
121 
122                 if(_response)
123                 {
124                     callback.response(_locatorInfo, _proxy);
125                 }
126                 else
127                 {
128                     Debug.Assert(_exception != null);
129                     callback.exception(_locatorInfo, _exception);
130                 }
131             }
132 
Request(LocatorInfo locatorInfo, Reference @ref)133             public Request(LocatorInfo locatorInfo, Reference @ref)
134             {
135                 _locatorInfo = locatorInfo;
136                 _ref = @ref;
137                 _sent = false;
138                 _response = false;
139             }
140 
141             public void
response(Ice.ObjectPrx proxy)142             response(Ice.ObjectPrx proxy)
143             {
144                 lock(this)
145                 {
146                     _locatorInfo.finishRequest(_ref, _wellKnownRefs, proxy, false);
147                     _response = true;
148                     _proxy = proxy;
149                     Monitor.PulseAll(this);
150                 }
151                 foreach(RequestCallback callback in _callbacks)
152                 {
153                     callback.response(_locatorInfo, proxy);
154                 }
155             }
156 
157             public void
exception(Ice.Exception ex)158             exception(Ice.Exception ex)
159             {
160                 lock(this)
161                 {
162                     _locatorInfo.finishRequest(_ref, _wellKnownRefs, null, ex is Ice.UserException);
163                     _exception = ex;
164                     Monitor.PulseAll(this);
165                 }
166                 foreach(RequestCallback callback in _callbacks)
167                 {
168                     callback.exception(_locatorInfo, ex);
169                 }
170             }
171 
send()172             protected abstract void send();
173 
174             readonly protected LocatorInfo _locatorInfo;
175             readonly protected Reference _ref;
176 
177             private List<RequestCallback> _callbacks = new List<RequestCallback>();
178             private List<Reference> _wellKnownRefs = new List<Reference>();
179             private bool _sent;
180             private bool _response;
181             private Ice.ObjectPrx _proxy;
182             private Ice.Exception _exception;
183         }
184 
185         private class ObjectRequest : Request
186         {
ObjectRequest(LocatorInfo locatorInfo, Reference @ref)187             public ObjectRequest(LocatorInfo locatorInfo, Reference @ref) : base(locatorInfo, @ref)
188             {
189             }
190 
191             override protected void
send()192             send()
193             {
194                 try
195                 {
196                     _locatorInfo.getLocator().begin_findObjectById(_ref.getIdentity()).whenCompleted(
197                         this.response, this.exception);
198                 }
199                 catch(Ice.Exception ex)
200                 {
201                     exception(ex);
202                 }
203             }
204         }
205 
206         private class AdapterRequest : Request
207         {
AdapterRequest(LocatorInfo locatorInfo, Reference @ref)208             public AdapterRequest(LocatorInfo locatorInfo, Reference @ref) : base(locatorInfo, @ref)
209             {
210             }
211 
212             override protected void
send()213             send()
214             {
215                 try
216                 {
217                     _locatorInfo.getLocator().begin_findAdapterById(_ref.getAdapterId()).whenCompleted(
218                         response, exception);
219                 }
220                 catch(Ice.Exception ex)
221                 {
222                     exception(ex);
223                 }
224             }
225         }
226 
LocatorInfo(Ice.LocatorPrx locator, LocatorTable table, bool background)227         internal LocatorInfo(Ice.LocatorPrx locator, LocatorTable table, bool background)
228         {
229             _locator = locator;
230             _table = table;
231             _background = background;
232         }
233 
destroy()234         public void destroy()
235         {
236             lock(this)
237             {
238                 _locatorRegistry = null;
239                 _table.clear();
240             }
241         }
242 
Equals(object obj)243         public override bool Equals(object obj)
244         {
245             if(ReferenceEquals(this, obj))
246             {
247                 return true;
248             }
249 
250             LocatorInfo rhs = obj as LocatorInfo;
251             return rhs == null ? false : _locator.Equals(rhs._locator);
252         }
253 
GetHashCode()254         public override int GetHashCode()
255         {
256             return _locator.GetHashCode();
257         }
258 
getLocator()259         public Ice.LocatorPrx getLocator()
260         {
261             //
262             // No synchronization necessary, _locator is immutable.
263             //
264             return _locator;
265         }
266 
getLocatorRegistry()267         public Ice.LocatorRegistryPrx getLocatorRegistry()
268         {
269             lock(this)
270             {
271                 if(_locatorRegistry != null)
272                 {
273                     return _locatorRegistry;
274                 }
275             }
276 
277             //
278             // Do not make locator calls from within sync.
279             //
280             Ice.LocatorRegistryPrx locatorRegistry = _locator.getRegistry();
281             if(locatorRegistry == null)
282             {
283                 return null;
284             }
285 
286             lock(this)
287             {
288                 //
289                 // The locator registry can't be located. We use ordered
290                 // endpoint selection in case the locator returned a proxy
291                 // with some endpoints which are prefered to be tried first.
292                 //
293                 _locatorRegistry = (Ice.LocatorRegistryPrx)locatorRegistry.ice_locator(null).ice_endpointSelection(
294                     Ice.EndpointSelectionType.Ordered);
295                 return _locatorRegistry;
296             }
297         }
298 
299         public void
300         getEndpoints(Reference @ref, int ttl, GetEndpointsCallback callback)
301         {
302             getEndpoints(@ref, null, ttl, callback);
303         }
304 
305         public void
306         getEndpoints(Reference @ref, Reference wellKnownRef, int ttl, GetEndpointsCallback callback)
307         {
308             Debug.Assert(@ref.isIndirect());
309             EndpointI[] endpoints = null;
310             bool cached = false;
311             if(!@ref.isWellKnown())
312             {
313                 endpoints = _table.getAdapterEndpoints(@ref.getAdapterId(), ttl, out cached);
314                 if(!cached)
315                 {
316                     if(_background && endpoints != null)
317                     {
318                         getAdapterRequest(@ref).addCallback(@ref, wellKnownRef, ttl, null);
319                     }
320                     else
321                     {
322                         getAdapterRequest(@ref).addCallback(@ref, wellKnownRef, ttl, callback);
323                         return;
324                     }
325                 }
326             }
327             else
328             {
329                 Reference r = _table.getObjectReference(@ref.getIdentity(), ttl, out cached);
330                 if(!cached)
331                 {
332                     if(_background && r != null)
333                     {
334                         getObjectRequest(@ref).addCallback(@ref, null, ttl, null);
335                     }
336                     else
337                     {
338                         getObjectRequest(@ref).addCallback(@ref, null, ttl, callback);
339                         return;
340                     }
341                 }
342 
343                 if(!r.isIndirect())
344                 {
345                     endpoints = r.getEndpoints();
346                 }
347                 else if(!r.isWellKnown())
348                 {
349                     if(@ref.getInstance().traceLevels().location >= 1)
350                     {
351                         trace("found adapter for well-known object in locator cache", @ref, r);
352                     }
353                     getEndpoints(r, @ref, ttl, callback);
354                     return;
355                 }
356             }
357 
358             Debug.Assert(endpoints != null);
359             if(@ref.getInstance().traceLevels().location >= 1)
360             {
361                 getEndpointsTrace(@ref, endpoints, true);
362             }
363             if(callback != null)
364             {
365                 callback.setEndpoints(endpoints, true);
366             }
367         }
368 
clearCache(Reference rf)369         public void clearCache(Reference rf)
370         {
371             Debug.Assert(rf.isIndirect());
372             if(!rf.isWellKnown())
373             {
374                 EndpointI[] endpoints = _table.removeAdapterEndpoints(rf.getAdapterId());
375 
376                 if(endpoints != null && rf.getInstance().traceLevels().location >= 2)
377                 {
378                     trace("removed endpoints for adapter from locator cache", rf, endpoints);
379                 }
380             }
381             else
382             {
383                 Reference r = _table.removeObjectReference(rf.getIdentity());
384                 if(r != null)
385                 {
386                     if(!r.isIndirect())
387                     {
388                         if(rf.getInstance().traceLevels().location >= 2)
389                         {
390                             trace("removed endpoints for well-known object from locator cache", rf, r.getEndpoints());
391                         }
392                     }
393                     else if(!r.isWellKnown())
394                     {
395                         if(rf.getInstance().traceLevels().location >= 2)
396                         {
397                             trace("removed adapter for well-known object from locator cache", rf, r);
398                         }
399                         clearCache(r);
400                     }
401                 }
402             }
403         }
404 
trace(string msg, Reference r, EndpointI[] endpoints)405         private void trace(string msg, Reference r, EndpointI[] endpoints)
406         {
407             System.Text.StringBuilder s = new System.Text.StringBuilder();
408             s.Append(msg + "\n");
409             if(r.getAdapterId().Length > 0)
410             {
411                 s.Append("adapter = " + r.getAdapterId() + "\n");
412             }
413             else
414             {
415                 s.Append("well-known proxy = " + r.ToString() + "\n");
416             }
417 
418             s.Append("endpoints = ");
419             int sz = endpoints.Length;
420             for (int i = 0; i < sz; i++)
421             {
422                 s.Append(endpoints[i].ToString());
423                 if(i + 1 < sz)
424                 {
425                     s.Append(":");
426                 }
427             }
428 
429             r.getInstance().initializationData().logger.trace(r.getInstance().traceLevels().locationCat, s.ToString());
430         }
431 
trace(string msg, Reference r, Reference resolved)432         private void trace(string msg, Reference r, Reference resolved)
433         {
434             Debug.Assert(r.isWellKnown());
435 
436             System.Text.StringBuilder s = new System.Text.StringBuilder();
437             s.Append(msg);
438             s.Append("\n");
439             s.Append("well-known proxy = ");
440             s.Append(r.ToString());
441             s.Append("\n");
442             s.Append("adapter = ");
443             s.Append(resolved.getAdapterId());
444 
445             r.getInstance().initializationData().logger.trace(r.getInstance().traceLevels().locationCat, s.ToString());
446         }
447 
448         private void getEndpointsException(Reference @ref, System.Exception exc)
449         {
450             try
451             {
452                 throw exc;
453             }
454             catch(Ice.AdapterNotFoundException ex)
455             {
456                 Instance instance = @ref.getInstance();
457                 if(instance.traceLevels().location >= 1)
458                 {
459                     System.Text.StringBuilder s = new System.Text.StringBuilder();
460                     s.Append("adapter not found\n");
461                     s.Append("adapter = " + @ref.getAdapterId());
462                     instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
463                 }
464 
465                 Ice.NotRegisteredException e = new Ice.NotRegisteredException(ex);
466                 e.kindOfObject = "object adapter";
467                 e.id = @ref.getAdapterId();
468                 throw e;
469             }
470             catch(Ice.ObjectNotFoundException ex)
471             {
472                 Instance instance = @ref.getInstance();
473                 if(instance.traceLevels().location >= 1)
474                 {
475                     System.Text.StringBuilder s = new System.Text.StringBuilder();
476                     s.Append("object not found\n");
477                     s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode()));
478                     instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
479                 }
480 
481                 Ice.NotRegisteredException e = new Ice.NotRegisteredException(ex);
482                 e.kindOfObject = "object";
483                 e.id = Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode());
484                 throw e;
485             }
486             catch(Ice.NotRegisteredException)
487             {
488                 throw;
489             }
490             catch(Ice.LocalException ex)
491             {
492                 Instance instance = @ref.getInstance();
493                 if(instance.traceLevels().location >= 1)
494                 {
495                     System.Text.StringBuilder s = new System.Text.StringBuilder();
496                     s.Append("couldn't contact the locator to retrieve endpoints\n");
497                     if(@ref.getAdapterId().Length > 0)
498                     {
499                         s.Append("adapter = " + @ref.getAdapterId() + "\n");
500                     }
501                     else
502                     {
503                         s.Append("well-known proxy = " + @ref.ToString() + "\n");
504                     }
505                     s.Append("reason = " + ex);
506                     instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
507                 }
508                 throw;
509             }
510             catch(System.Exception)
511             {
512                 Debug.Assert(false);
513             }
514         }
515 
516         private void getEndpointsTrace(Reference @ref, EndpointI[] endpoints, bool cached)
517         {
518             if(endpoints != null && endpoints.Length > 0)
519             {
520                 if(cached)
521                 {
522                     if(@ref.isWellKnown())
523                     {
524                         trace("found endpoints for well-known proxy in locator cache", @ref, endpoints);
525                     }
526                     else
527                     {
528                         trace("found endpoints for adapter in locator cache", @ref, endpoints);
529                     }
530                 }
531                 else
532                 {
533                     if(@ref.isWellKnown())
534                     {
535                         trace("retrieved endpoints for well-known proxy from locator, adding to locator cache",
536                               @ref, endpoints);
537                     }
538                     else
539                     {
540                         trace("retrieved endpoints for adapter from locator, adding to locator cache",
541                               @ref, endpoints);
542                     }
543                 }
544             }
545             else
546             {
547                 Instance instance = @ref.getInstance();
548                 System.Text.StringBuilder s = new System.Text.StringBuilder();
549                 s.Append("no endpoints configured for ");
550                 if(@ref.getAdapterId().Length > 0)
551                 {
552                     s.Append("adapter\n");
553                     s.Append("adapter = " + @ref.getAdapterId());
554                 }
555                 else
556                 {
557                     s.Append("well-known object\n");
558                     s.Append("well-known proxy = " + @ref.ToString());
559                 }
560                 instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
561             }
562         }
563 
564         private Request
565         getAdapterRequest(Reference @ref)
566         {
567             if(@ref.getInstance().traceLevels().location >= 1)
568             {
569                 Instance instance = @ref.getInstance();
570                 System.Text.StringBuilder s = new System.Text.StringBuilder();
571                 s.Append("searching for adapter by id\nadapter = ");
572                 s.Append(@ref.getAdapterId());
573                 instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
574             }
575 
576             lock(this)
577             {
578                 Request request;
579                 if(_adapterRequests.TryGetValue(@ref.getAdapterId(), out request))
580                 {
581                     return request;
582                 }
583 
584                 request = new AdapterRequest(this, @ref);
585                 _adapterRequests.Add(@ref.getAdapterId(), request);
586                 return request;
587             }
588         }
589 
590         private Request
591         getObjectRequest(Reference @ref)
592         {
593             if(@ref.getInstance().traceLevels().location >= 1)
594             {
595                 Instance instance = @ref.getInstance();
596                 System.Text.StringBuilder s = new System.Text.StringBuilder();
597                 s.Append("searching for well-known object\nwell-known proxy = ");
598                 s.Append(@ref.ToString());
599                 instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString());
600             }
601 
602             lock(this)
603             {
604                 Request request;
605                 if(_objectRequests.TryGetValue(@ref.getIdentity(), out request))
606                 {
607                     return request;
608                 }
609 
610                 request = new ObjectRequest(this, @ref);
611                 _objectRequests.Add(@ref.getIdentity(), request);
612                 return request;
613             }
614         }
615 
616         private void
617         finishRequest(Reference @ref, List<Reference> wellKnownRefs, Ice.ObjectPrx proxy, bool notRegistered)
618         {
619             Ice.ObjectPrxHelperBase @base = proxy as Ice.ObjectPrxHelperBase;
620             if(proxy == null || @base.iceReference().isIndirect())
621             {
622                 //
623                 // Remove the cached references of well-known objects for which we tried
624                 // to resolved the endpoints if these endpoints are empty.
625                 //
626                 foreach(Reference r in wellKnownRefs)
627                 {
628                     _table.removeObjectReference(r.getIdentity());
629                 }
630             }
631 
632             if(!@ref.isWellKnown())
633             {
634                 if(proxy != null && !@base.iceReference().isIndirect())
635                 {
636                     // Cache the adapter endpoints.
637                     _table.addAdapterEndpoints(@ref.getAdapterId(), @base.iceReference().getEndpoints());
638                 }
639                 else if(notRegistered) // If the adapter isn't registered anymore, remove it from the cache.
640                 {
641                     _table.removeAdapterEndpoints(@ref.getAdapterId());
642                 }
643 
644                 lock(this)
645                 {
646                     Debug.Assert(_adapterRequests.ContainsKey(@ref.getAdapterId()));
647                     _adapterRequests.Remove(@ref.getAdapterId());
648                 }
649             }
650             else
651             {
652                 if(proxy != null && !@base.iceReference().isWellKnown())
653                 {
654                     // Cache the well-known object reference.
655                     _table.addObjectReference(@ref.getIdentity(), @base.iceReference());
656                 }
657                 else if(notRegistered) // If the well-known object isn't registered anymore, remove it from the cache.
658                 {
659                     _table.removeObjectReference(@ref.getIdentity());
660                 }
661 
662                 lock(this)
663                 {
664                     Debug.Assert(_objectRequests.ContainsKey(@ref.getIdentity()));
665                     _objectRequests.Remove(@ref.getIdentity());
666                 }
667             }
668         }
669 
670         private readonly Ice.LocatorPrx _locator;
671         private Ice.LocatorRegistryPrx _locatorRegistry;
672         private readonly LocatorTable _table;
673         private readonly bool _background;
674 
675         private Dictionary<string, Request> _adapterRequests = new Dictionary<string, Request>();
676         private Dictionary<Ice.Identity, Request> _objectRequests = new Dictionary<Ice.Identity, Request>();
677     }
678 
679     public sealed class LocatorManager
680     {
681         struct LocatorKey
682         {
LocatorKeyIceInternal.LocatorManager.LocatorKey683             public LocatorKey(Ice.LocatorPrx prx)
684             {
685                 Reference r = ((Ice.ObjectPrxHelperBase)prx).iceReference();
686                 _id = r.getIdentity();
687                 _encoding = r.getEncoding();
688             }
689 
EqualsIceInternal.LocatorManager.LocatorKey690             public override bool Equals(object o)
691             {
692                 LocatorKey k = (LocatorKey)o;
693                 if(!k._id.Equals(_id))
694                 {
695                     return false;
696                 }
697                 if(!k._encoding.Equals(_encoding))
698                 {
699                     return false;
700                 }
701                 return true;
702             }
703 
GetHashCodeIceInternal.LocatorManager.LocatorKey704             public override int GetHashCode()
705             {
706                 int h = 5381;
707                 HashUtil.hashAdd(ref h, _id);
708                 HashUtil.hashAdd(ref h, _encoding);
709                 return h;
710             }
711 
712             private Ice.Identity _id;
713             private Ice.EncodingVersion _encoding;
714         }
715 
LocatorManager(Ice.Properties properties)716         internal LocatorManager(Ice.Properties properties)
717         {
718             _table = new Dictionary<Ice.LocatorPrx, LocatorInfo>();
719             _locatorTables = new Dictionary<LocatorKey, LocatorTable>();
720             _background = properties.getPropertyAsInt("Ice.BackgroundLocatorCacheUpdates") > 0;
721         }
722 
destroy()723         internal void destroy()
724         {
725             lock(this)
726             {
727                 foreach(LocatorInfo info in _table.Values)
728                 {
729                     info.destroy();
730                 }
731                 _table.Clear();
732                 _locatorTables.Clear();
733             }
734         }
735 
736         //
737         // Returns locator info for a given locator. Automatically creates
738         // the locator info if it doesn't exist yet.
739         //
get(Ice.LocatorPrx loc)740         public LocatorInfo get(Ice.LocatorPrx loc)
741         {
742             if(loc == null)
743             {
744                 return null;
745             }
746 
747             //
748             // The locator can't be located.
749             //
750             Ice.LocatorPrx locator = Ice.LocatorPrxHelper.uncheckedCast(loc.ice_locator(null));
751 
752             //
753             // TODO: reap unused locator info objects?
754             //
755             lock(this)
756             {
757                 LocatorInfo info = null;
758                 if(!_table.TryGetValue(locator, out info))
759                 {
760                     //
761                     // Rely on locator identity for the adapter table. We want to
762                     // have only one table per locator (not one per locator
763                     // proxy).
764                     //
765                     LocatorTable table = null;
766                     LocatorKey key = new LocatorKey(locator);
767                     if(!_locatorTables.TryGetValue(key, out table))
768                     {
769                         table = new LocatorTable();
770                         _locatorTables[key] = table;
771                     }
772 
773                     info = new LocatorInfo(locator, table, _background);
774                     _table[locator] = info;
775                 }
776 
777                 return info;
778             }
779         }
780 
781         private Dictionary<Ice.LocatorPrx, LocatorInfo> _table;
782         private Dictionary<LocatorKey, LocatorTable> _locatorTables;
783         private readonly bool _background;
784     }
785 
786     sealed class LocatorTable
787     {
LocatorTable()788         internal LocatorTable()
789         {
790             _adapterEndpointsTable = new Dictionary<string, EndpointTableEntry>();
791             _objectTable = new Dictionary<Ice.Identity, ReferenceTableEntry>();
792         }
793 
clear()794         internal void clear()
795         {
796             lock(this)
797             {
798                 _adapterEndpointsTable.Clear();
799                 _objectTable.Clear();
800             }
801         }
802 
getAdapterEndpoints(string adapter, int ttl, out bool cached)803         internal EndpointI[] getAdapterEndpoints(string adapter, int ttl, out bool cached)
804         {
805             if(ttl == 0) // Locator cache disabled.
806             {
807                 cached = false;
808                 return null;
809             }
810 
811             lock(this)
812             {
813                 EndpointTableEntry entry = null;
814                 if(_adapterEndpointsTable.TryGetValue(adapter, out entry))
815                 {
816                     cached = checkTTL(entry.time, ttl);
817                     return entry.endpoints;
818 
819                 }
820                 cached = false;
821                 return null;
822             }
823         }
824 
addAdapterEndpoints(string adapter, EndpointI[] endpoints)825         internal void addAdapterEndpoints(string adapter, EndpointI[] endpoints)
826         {
827             lock(this)
828             {
829                 _adapterEndpointsTable[adapter] =
830                     new EndpointTableEntry(Time.currentMonotonicTimeMillis(), endpoints);
831             }
832         }
833 
removeAdapterEndpoints(string adapter)834         internal EndpointI[] removeAdapterEndpoints(string adapter)
835         {
836             lock(this)
837             {
838                 EndpointTableEntry entry = null;
839                 if(_adapterEndpointsTable.TryGetValue(adapter, out entry))
840                 {
841                     _adapterEndpointsTable.Remove(adapter);
842                     return entry.endpoints;
843                 }
844                 return null;
845             }
846         }
847 
getObjectReference(Ice.Identity id, int ttl, out bool cached)848         internal Reference getObjectReference(Ice.Identity id, int ttl, out bool cached)
849         {
850             if(ttl == 0) // Locator cache disabled.
851             {
852                 cached = false;
853                 return null;
854             }
855 
856             lock(this)
857             {
858                 ReferenceTableEntry entry = null;
859                 if(_objectTable.TryGetValue(id, out entry))
860                 {
861                     cached = checkTTL(entry.time, ttl);
862                     return entry.reference;
863                 }
864                 cached = false;
865                 return null;
866             }
867         }
868 
addObjectReference(Ice.Identity id, Reference reference)869         internal void addObjectReference(Ice.Identity id, Reference reference)
870         {
871             lock(this)
872             {
873                 _objectTable[id] = new ReferenceTableEntry(Time.currentMonotonicTimeMillis(), reference);
874             }
875         }
876 
removeObjectReference(Ice.Identity id)877         internal Reference removeObjectReference(Ice.Identity id)
878         {
879             lock(this)
880             {
881                 ReferenceTableEntry entry = null;
882                 if(_objectTable.TryGetValue(id, out entry))
883                 {
884                     _objectTable.Remove(id);
885                     return entry.reference;
886                 }
887                 return null;
888             }
889         }
890 
checkTTL(long time, int ttl)891         private bool checkTTL(long time, int ttl)
892         {
893             Debug.Assert(ttl != 0);
894             if(ttl < 0) // TTL = infinite
895             {
896                 return true;
897             }
898             else
899             {
900                 return Time.currentMonotonicTimeMillis() - time <= ((long)ttl * 1000);
901             }
902         }
903 
904         sealed private class EndpointTableEntry
905         {
EndpointTableEntry(long time, EndpointI[] endpoints)906             public EndpointTableEntry(long time, EndpointI[] endpoints)
907             {
908                 this.time = time;
909                 this.endpoints = endpoints;
910             }
911 
912             public long time;
913             public EndpointI[] endpoints;
914         }
915 
916         sealed private class ReferenceTableEntry
917         {
ReferenceTableEntry(long time, Reference reference)918             public ReferenceTableEntry(long time, Reference reference)
919             {
920                 this.time = time;
921                 this.reference = reference;
922             }
923 
924             public long time;
925             public Reference reference;
926         }
927 
928         private Dictionary<string, EndpointTableEntry> _adapterEndpointsTable;
929         private Dictionary<Ice.Identity, ReferenceTableEntry> _objectTable;
930     }
931 
932 }
933