A servant locator has the following interface:
module Ice { local interface ServantLocator { ["java:UserException"] Object locate(Current curr, out LocalObject cookie); ["java:UserException"] void finished(Current curr, Object servant, LocalObject cookie); void deactivate(string category); } }
Note that ServantLocator
is a local interface. To create an actual implementation of a servant locator, you must define a class that is derived from Ice::ServantLocator
and provide implementations of the locate
, finished
, and deactivate
operations. The Ice run time invokes the operations on your derived class as follows:
locate
Whenever a request arrives for which no entry exists in the active servant map (ASM), the Ice run time callslocate
and supplies theCurrent
object for the request. The implementation oflocate
(which you provide as part of the derived class) is supposed to return a servant that can process the incoming request. Your implementation oflocate
can behave in three possible ways:
You can also throw user exceptions fromlocate
. If the user exception is in the corresponding operation's exception specification, that user exception is returned to the client. User exceptions thrown bylocate
that are not listed in the exception specification of the corresponding operation are also returned to the client, and then thrown in the client asUnknownUserException
. Non-Ice exceptions are returned to the client asUnknownException
.
Thecookie
out-parameter tolocate
allows you to return a local object to the object adapter. The object adapter does not care about the contents of that object (and it is legal to return a null cookie). Instead, the Ice run time passes whatever cookie you return fromlocate
back to you when it callsfinished
. This allows you to pass an arbitrary amount of state fromlocate
to the corresponding call tofinished
.
finished
If a call tolocate
has returned a servant to the Ice run time, the Ice run time dispatches the incoming request to the servant. Once the request is complete (that is, the operation being invoked has completed), the Ice run time callsfinished
, passing the servant whose operation has completed, theCurrent
object for the request, and the cookie that was initially created bylocate
. This means that every call tolocate
is balanced by a corresponding call tofinished
(provided thatlocate
actually returned a servant).
If you throw an exception fromfinished
, the Ice run time propagates the thrown exception back to the client. As forlocate
, you can throw user exceptions fromfinished
. If a user exception is in the corresponding operation's exception specification, that user exception is returned to the client. User exceptions that are not in the corresponding operation's exception specification are also returned to the client, and then thrown by the client asUnknownUserException
.
finished
can also throw run-time exceptions. However, onlyObjectNotExistException
,OperationNotExistException
, andFacetNotExistException
are propagated without change to the client; other run-time exceptions are returned to the client asUnknownLocalException
.
Non-Ice exceptions thrown fromfinished
are returned to the client asUnknownException
.
If both the operation implementation andfinished
throw a user exception, the exception thrown byfinished
overrides the exception thrown by the operation.
deactivate
Thedeactivate
operation allows a servant locator to clean up once it is no longer needed. (For example, the locator might close a database connection.) The Ice run time passes the category of the servant locator being deactivated to thedeactivate
operation.
The run time callsdeactivate
when destroying the object adapter to which the servant locator is attached. More precisely,deactivate
is called when you calldestroy
on the object adapter, or when you calldestroy
on the communicator (which implicitly callsdestroy
on the object adapter).
Once the run time has calleddeactivate
, it is guaranteed that no further calls tolocate
orfinished
can happen, that is,deactivate
is called exactly once, after all operations dispatched via this servant locator have completed.
This also explains whydeactivate
is not called as part ofObjectAdapter::deactivate
:ObjectAdapter::deactivate
initiates deactivation and returns immediately, so it cannot callServantLocator::deactivate
directly, because there might still be outstanding requests dispatched via this servant locator that have to complete first — in turn, this would mean that eitherObjectAdapter::deactivate
could block (which it must not do) or that a call toServantLocator::deactivate
could be followed by one or more calls tofinished
(which must not happen either).
It is important to realize that the Ice run time does not "remember" the servant that is returned by a particular call to locate
. Instead, the Ice run time simply dispatches an incoming request to the servant returned by locate
and, once the request is complete, calls finished
. In particular, if two requests for the same servant arrive more or less simultaneously, the Ice run time calls locate
and finished
once for each request. In other words, locate
establishes the association between an object identity and a servant; that association is valid only for a single request and is never used by the Ice run time to dispatch a different request.