RouterInfo.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
final class RouterInfo {
interface GetClientEndpointsCallback {
void setEndpoints(EndpointI[] endpoints);
void setException(LocalException ex);
}
interface AddProxyCallback {
void addedProxy();
void setException(LocalException ex);
}
RouterInfo(RouterPrx router) {
_router = router;
assert (_router != null);
}
public synchronized void destroy() {
_clientEndpoints = new EndpointI[0];
_adapter = null;
_identities.clear();
}
@Override
public boolean equals(java.lang.Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof RouterInfo) {
return _router.equals(((RouterInfo) obj)._router);
}
return false;
}
@Override
public int hashCode() {
return _router.hashCode();
}
public RouterPrx getRouter() {
// No mutex lock necessary, _router is immutable.
return _router;
}
public EndpointI[] getClientEndpoints() {
synchronized (this) {
// Lazy initialization.
if (_clientEndpoints != null) {
return _clientEndpoints;
}
}
Router.GetClientProxyResult r = _router.getClientProxy();
return setClientEndpoints(r.returnValue, r.hasRoutingTable.orElse(true));
}
public void getClientEndpoints(final GetClientEndpointsCallback callback) {
EndpointI[] clientEndpoints = null;
synchronized (this) {
clientEndpoints = _clientEndpoints;
}
if (clientEndpoints != null) {
callback.setEndpoints(clientEndpoints);
return;
}
_router.getClientProxyAsync()
.whenComplete(
(Router.GetClientProxyResult r, Throwable ex) -> {
if (ex != null) {
if (ex instanceof LocalException) {
callback.setException((LocalException) ex);
} else {
callback.setException(new UnknownException(ex));
}
} else {
callback.setEndpoints(
setClientEndpoints(
r.returnValue, r.hasRoutingTable.orElse(true)));
}
});
}
public EndpointI[] getServerEndpoints() {
ObjectPrx serverProxy = _router.getServerProxy();
if (serverProxy == null) {
throw new NoEndpointException("Router::getServerProxy returned a null proxy.");
}
serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed.
return ((_ObjectPrxI) serverProxy)._getReference().getEndpoints();
}
public boolean addProxy(final Reference reference, final AddProxyCallback callback) {
Identity identity = reference.getIdentity();
synchronized (this) {
if (!_hasRoutingTable) {
return true; // The router implementation doesn't maintain a routing table.
}
if (_identities.contains(identity)) {
//
// Only add the proxy to the router if it's not already in our local map.
//
return true;
}
}
_router.addProxiesAsync(new ObjectPrx[]{new _ObjectPrxI(reference)})
.whenComplete(
(ObjectPrx[] evictedProxies, Throwable ex) -> {
if (ex != null) {
if (ex instanceof LocalException) {
callback.setException((LocalException) ex);
} else {
callback.setException(new UnknownException(ex));
}
} else {
addAndEvictProxies(identity, evictedProxies);
callback.addedProxy();
}
});
return false;
}
public synchronized void setAdapter(ObjectAdapter adapter) {
_adapter = adapter;
}
public synchronized ObjectAdapter getAdapter() {
return _adapter;
}
public synchronized void clearCache(Reference ref) {
_identities.remove(ref.getIdentity());
}
private synchronized EndpointI[] setClientEndpoints(
ObjectPrx clientProxy, boolean hasRoutingTable) {
if (_clientEndpoints == null) {
_hasRoutingTable = hasRoutingTable;
_clientEndpoints =
clientProxy == null
? ((_ObjectPrxI) _router)._getReference().getEndpoints()
: ((_ObjectPrxI) clientProxy)._getReference().getEndpoints();
}
return _clientEndpoints;
}
private synchronized void addAndEvictProxies(Identity identity, ObjectPrx[] evictedProxies) {
//
// Check if the proxy hasn't already been evicted by a concurrent addProxies call. If it's
// the case, don't add it to our local map.
//
int index = _evictedIdentities.indexOf(identity);
if (index >= 0) {
_evictedIdentities.remove(index);
} else {
//
// If we successfully added the proxy to the router, we add it to our local map.
//
_identities.add(identity);
}
//
// We also must remove whatever proxies the router evicted.
//
for (ObjectPrx p : evictedProxies) {
if (!_identities.remove(p.ice_getIdentity())) {
//
// It's possible for the proxy to not have been added yet in the local map if two
// threads concurrently call addProxies.
//
_evictedIdentities.add(p.ice_getIdentity());
}
}
}
private final RouterPrx _router;
private EndpointI[] _clientEndpoints;
private ObjectAdapter _adapter;
private final Set<Identity> _identities = new HashSet<>();
private final List<Identity> _evictedIdentities = new ArrayList<>();
private boolean _hasRoutingTable;
}