com.zeroc.IceLocatorDiscovery.PluginI Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of icelocatordiscovery Show documentation
Show all versions of icelocatordiscovery Show documentation
Ice plug-in that enables the discovery of IceGrid and custom locators via UDP multicast
The newest version!
//
// Copyright (c) ZeroC, Inc. All rights reserved.
//
package com.zeroc.IceLocatorDiscovery;
import com.zeroc.IceInternal.Network;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
class PluginI implements Plugin
{
private static class Request
{
Request(LocatorI locator,
String operation,
com.zeroc.Ice.OperationMode mode,
byte[] inParams,
java.util.Map context,
CompletableFuture f)
{
_locator = locator;
_operation = operation;
_mode = mode;
_inParams = inParams;
_context = context;
_future = f;
}
void invoke(com.zeroc.Ice.LocatorPrx l)
{
if(_locatorPrx == null || !_locatorPrx.equals(l))
{
_locatorPrx = l;
try
{
final CompletableFuture f =
l.ice_invokeAsync(_operation, _mode, _inParams, _context);
f.whenComplete((result, ex) ->
{
if(ex != null)
{
exception((com.zeroc.Ice.LocalException)ex);
}
else
{
_future.complete(result);
}
});
}
catch(com.zeroc.Ice.LocalException ex)
{
exception(ex);
}
}
else
{
assert(_exception != null); // Don't retry if the proxy didn't change
exception(_exception);
}
}
private void exception(com.zeroc.Ice.LocalException ex)
{
try
{
throw ex;
}
catch(com.zeroc.Ice.RequestFailedException exc)
{
_future.completeExceptionally(ex);
}
catch(com.zeroc.Ice.UnknownException exc)
{
_future.completeExceptionally(ex);
}
catch(com.zeroc.Ice.NoEndpointException exc)
{
_future.completeExceptionally(new com.zeroc.Ice.ObjectNotExistException());
}
catch(com.zeroc.Ice.ObjectAdapterDeactivatedException exc)
{
_future.completeExceptionally(new com.zeroc.Ice.ObjectNotExistException());
}
catch(com.zeroc.Ice.CommunicatorDestroyedException exc)
{
_future.completeExceptionally(new com.zeroc.Ice.ObjectNotExistException());
}
catch(com.zeroc.Ice.LocalException exc)
{
_exception = exc;
_locator.invoke(_locatorPrx, Request.this); // Retry with new locator proxy
}
}
private final LocatorI _locator;
private com.zeroc.Ice.LocalException _exception = null;
private final String _operation;
private final com.zeroc.Ice.OperationMode _mode;
private final java.util.Map _context;
private final byte[] _inParams;
private final CompletableFuture _future;
private com.zeroc.Ice.LocatorPrx _locatorPrx;
}
static private class VoidLocatorI implements com.zeroc.Ice.Locator
{
@Override
public CompletionStage findObjectByIdAsync(com.zeroc.Ice.Identity id,
com.zeroc.Ice.Current current)
{
return CompletableFuture.completedFuture((com.zeroc.Ice.ObjectPrx)null);
}
@Override
public CompletionStage findAdapterByIdAsync(String id, com.zeroc.Ice.Current current)
{
return CompletableFuture.completedFuture((com.zeroc.Ice.ObjectPrx)null);
}
@Override
public com.zeroc.Ice.LocatorRegistryPrx getRegistry(com.zeroc.Ice.Current current)
{
return null;
}
}
private static class LocatorI implements com.zeroc.Ice.BlobjectAsync
{
LocatorI(String name, LookupPrx lookup, com.zeroc.Ice.Properties properties, String instanceName,
com.zeroc.Ice.LocatorPrx voidLocator)
{
_lookup = lookup;
_timeout = properties.getPropertyAsIntWithDefault(name + ".Timeout", 300);
if(_timeout < 0)
{
_timeout = 300;
}
_retryCount = properties.getPropertyAsIntWithDefault(name + ".RetryCount", 3);
if(_retryCount < 0)
{
_retryCount = 0;
}
_retryDelay = properties.getPropertyAsIntWithDefault(name + ".RetryDelay", 2000);
if(_retryDelay < 0)
{
_retryDelay = 0;
}
_timer = com.zeroc.IceInternal.Util.getInstance(lookup.ice_getCommunicator()).timer();
_traceLevel = properties.getPropertyAsInt(name + ".Trace.Lookup");
_instanceName = instanceName;
_warned = false;
_locator = lookup.ice_getCommunicator().getDefaultLocator();
_voidLocator = voidLocator;
_pendingRetryCount = 0;
_pending = false;
_failureCount = 0;
_warnOnce = true;
//
// Create one lookup proxy per endpoint from the given proxy. We want to send a multicast
// datagram on each endpoint.
//
com.zeroc.Ice.Endpoint[] single = new com.zeroc.Ice.Endpoint[1];
for(com.zeroc.Ice.Endpoint endpt : lookup.ice_getEndpoints())
{
single[0] = endpt;
_lookups.put((LookupPrx)lookup.ice_endpoints(single), null);
}
assert(!_lookups.isEmpty());
}
public void setLookupReply(LookupReplyPrx lookupReply)
{
//
// Use a lookup reply proxy whose adress matches the interface used to send multicast datagrams.
//
com.zeroc.Ice.Endpoint[] single = new com.zeroc.Ice.Endpoint[1];
for(Map.Entry entry : _lookups.entrySet())
{
com.zeroc.Ice.UDPEndpointInfo info =
(com.zeroc.Ice.UDPEndpointInfo)entry.getKey().ice_getEndpoints()[0].getInfo();
if(!info.mcastInterface.isEmpty())
{
for(com.zeroc.Ice.Endpoint q : lookupReply.ice_getEndpoints())
{
com.zeroc.Ice.EndpointInfo r = q.getInfo();
if(r instanceof com.zeroc.Ice.IPEndpointInfo &&
((com.zeroc.Ice.IPEndpointInfo)r).host.equals(info.mcastInterface))
{
single[0] = q;
entry.setValue((LookupReplyPrx)lookupReply.ice_endpoints(single));
}
}
}
if(entry.getValue() == null)
{
// Fallback: just use the given lookup reply proxy if no matching endpoint found.
entry.setValue(lookupReply);
}
}
}
@Override
public CompletionStage ice_invokeAsync(byte[] inParams,
com.zeroc.Ice.Current current)
{
CompletableFuture f = new CompletableFuture<>();
invoke(null, new Request(this, current.operation, current.mode, inParams, current.ctx, f));
return f;
}
public List getLocators(String instanceName, int waitTime)
{
//
// Clear locators from previous search.
//
synchronized(this)
{
_locators.clear();
}
//
// Find a locator
//
invoke(null, null);
//
// Wait for responses
//
try
{
if(instanceName.isEmpty())
{
Thread.sleep(waitTime);
}
else
{
synchronized(this)
{
while(!_locators.containsKey(instanceName) && _pending)
{
wait(waitTime);
}
}
}
}
catch(java.lang.InterruptedException ex)
{
throw new com.zeroc.Ice.OperationInterruptedException();
}
//
// Return found locators
//
synchronized(this)
{
return new ArrayList<>(_locators.values());
}
}
public synchronized void foundLocator(com.zeroc.Ice.LocatorPrx locator)
{
if(locator == null)
{
if(_traceLevel > 2)
{
_lookup.ice_getCommunicator().getLogger().trace("Lookup", "ignoring locator reply: (null locator)");
}
return;
}
if(!_instanceName.isEmpty() && !locator.ice_getIdentity().category.equals(_instanceName))
{
if(_traceLevel > 2)
{
StringBuffer s = new StringBuffer("ignoring locator reply: instance name doesn't match\n");
s.append("expected = ").append(_instanceName);
s.append("received = ").append(locator.ice_getIdentity().category);
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
return;
}
//
// If we already have a locator assigned, ensure the given locator
// has the same identity, otherwise ignore it.
//
if(!_pendingRequests.isEmpty() &&
_locator != null && !locator.ice_getIdentity().category.equals(_locator.ice_getIdentity().category))
{
if(!_warned)
{
_warned = true; // Only warn once
locator.ice_getCommunicator().getLogger().warning(
"received Ice locator with different instance name:\n" +
"using = `" + _locator.ice_getIdentity().category + "'\n" +
"received = `" + locator.ice_getIdentity().category + "'\n" +
"This is typically the case if multiple Ice locators with different " +
"instance names are deployed and the property `IceLocatorDiscovery.InstanceName'" +
"is not set.");
}
return;
}
if(_pending) // No need to continue, we found a locator
{
_future.cancel(false);
_future = null;
_pendingRetryCount = 0;
_pending = false;
}
if(_traceLevel > 0)
{
StringBuffer s = new StringBuffer("locator lookup succeeded:\nlocator = ");
s.append(locator);
if(!_instanceName.isEmpty())
{
s.append("\ninstance name = ").append(_instanceName);
}
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
com.zeroc.Ice.LocatorPrx l =
_pendingRequests.isEmpty() ? _locators.get(locator.ice_getIdentity().category) : _locator;
if(l != null)
{
//
// We found another locator replica, append its endpoints to the
// current locator proxy endpoints.
//
List newEndpoints = new ArrayList<>(Arrays.asList(l.ice_getEndpoints()));
for(com.zeroc.Ice.Endpoint p : locator.ice_getEndpoints())
{
//
// Only add endpoints if not already in the locator proxy endpoints
//
boolean found = false;
for(com.zeroc.Ice.Endpoint q : newEndpoints)
{
if(p.equals(q))
{
found = true;
break;
}
}
if(!found)
{
newEndpoints.add(p);
}
}
l = (com.zeroc.Ice.LocatorPrx)l.ice_endpoints(
newEndpoints.toArray(new com.zeroc.Ice.Endpoint[newEndpoints.size()]));
}
else
{
l = locator;
}
if(_pendingRequests.isEmpty())
{
_locators.put(locator.ice_getIdentity().category, l);
notify();
}
else
{
_locator = l;
if(_instanceName.isEmpty())
{
_instanceName = _locator.ice_getIdentity().category; // Stick to the first locator
}
//
// Send pending requests if any.
//
for(Request req : _pendingRequests)
{
req.invoke(_locator);
}
_pendingRequests.clear();
}
}
public synchronized void invoke(com.zeroc.Ice.LocatorPrx locator, Request request)
{
if(request != null && _locator != null && _locator != locator)
{
request.invoke(_locator);
}
else if(request != null && com.zeroc.IceInternal.Time.currentMonotonicTimeMillis() < _nextRetry)
{
request.invoke(_voidLocator); // Don't retry to find a locator before the retry delay expires
}
else
{
_locator = null;
if(request != null)
{
_pendingRequests.add(request);
}
if(!_pending) // No request in progress
{
_pending = true;
_pendingRetryCount = _retryCount;
_failureCount = 0;
try
{
if(_traceLevel > 1)
{
StringBuilder s = new StringBuilder("looking up locator:\nlookup = ");
s.append(_lookup);
if(!_instanceName.isEmpty())
{
s.append("\ninstance name = ").append(_instanceName);
}
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
for(Map.Entry entry : _lookups.entrySet())
{
entry.getKey().findLocatorAsync(_instanceName,
entry.getValue()).whenCompleteAsync((v, ex) -> {
if(ex != null)
{
exception(ex);
}
}, entry.getKey().ice_executor()); // Send multicast request.
}
_future = _timer.schedule(_retryTask, _timeout, java.util.concurrent.TimeUnit.MILLISECONDS);
}
catch(com.zeroc.Ice.LocalException ex)
{
if(_traceLevel > 0)
{
StringBuilder s = new StringBuilder("locator lookup failed:\nlookup = ");
s.append(_lookup);
if(!_instanceName.isEmpty())
{
s.append("\ninstance name = ").append(_instanceName);
}
s.append("\n").append(ex);
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
for(Request req : _pendingRequests)
{
req.invoke(_voidLocator);
}
_pendingRequests.clear();
_pending = false;
_pendingRetryCount = 0;
}
}
}
}
synchronized void exception(Throwable ex)
{
if(++_failureCount == _lookups.size() && _pending)
{
//
// All the lookup calls failed, cancel the timer and propagate the error to the requests.
//
_future.cancel(false);
_future = null;
_pendingRetryCount = 0;
_pending = false;
if(_warnOnce)
{
StringBuilder builder = new StringBuilder();
builder.append("failed to lookup locator with lookup proxy `");
builder.append(_lookup);
builder.append("':\n");
builder.append(ex);
_lookup.ice_getCommunicator().getLogger().warning(builder.toString());
_warnOnce = false;
}
if(_traceLevel > 0)
{
StringBuilder s = new StringBuilder("locator lookup failed:\nlookup = ");
s.append(_lookup);
if(!_instanceName.isEmpty())
{
s.append("\ninstance name = ").append(_instanceName);
}
s.append("\n").append(ex);
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
if(_pendingRequests.isEmpty())
{
notify();
}
else
{
for(Request req : _pendingRequests)
{
req.invoke(_voidLocator);
}
_pendingRequests.clear();
}
}
}
private Runnable _retryTask = new Runnable()
{
@Override
public void run()
{
synchronized(LocatorI.this)
{
if(!_pending)
{
assert(_pendingRequests.isEmpty());
return; // Request failed
}
if(_pendingRetryCount > 0)
{
--_pendingRetryCount;
try
{
if(_traceLevel > 1)
{
StringBuilder s = new StringBuilder("retrying locator lookup:\nlookup = ");
s.append(_lookup);
s.append("\nretry count = ").append(_retryCount);
if(!_instanceName.isEmpty())
{
s.append("\ninstance name = ").append(_instanceName);
}
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
_failureCount = 0;
for(Map.Entry entry : _lookups.entrySet())
{
entry.getKey().findLocatorAsync(_instanceName,
entry.getValue()).whenCompleteAsync((v, ex) -> {
if(ex != null)
{
exception(ex);
}
}, entry.getKey().ice_executor()); // Send multicast request.
}
_future = _timer.schedule(_retryTask, _timeout, java.util.concurrent.TimeUnit.MILLISECONDS);
return;
}
catch(com.zeroc.Ice.LocalException ex)
{
}
_pendingRetryCount = 0;
}
assert(_pendingRetryCount == 0);
_pending = false;
if(_traceLevel > 0)
{
StringBuilder s = new StringBuilder("locator lookup timed out:\nlookup = ");
s.append(_lookup);
if(!_instanceName.isEmpty())
{
s.append("\ninstance name = ").append(_instanceName);
}
_lookup.ice_getCommunicator().getLogger().trace("Lookup", s.toString());
}
if(_pendingRequests.isEmpty())
{
notify();
}
else
{
for(Request req : _pendingRequests)
{
req.invoke(_voidLocator);
}
_pendingRequests.clear();
}
_nextRetry = com.zeroc.IceInternal.Time.currentMonotonicTimeMillis() + _retryDelay;
}
}
};
private final LookupPrx _lookup;
private final Map _lookups = new java.util.HashMap<>();
private int _timeout;
private java.util.concurrent.Future> _future;
private final java.util.concurrent.ScheduledExecutorService _timer;
private final int _traceLevel;
private int _retryCount;
private int _retryDelay;
private String _instanceName;
private boolean _warned;
private com.zeroc.Ice.LocatorPrx _locator;
private com.zeroc.Ice.LocatorPrx _voidLocator;
private Map _locators = new HashMap<>();
private boolean _pending;
private int _pendingRetryCount;
private int _failureCount;
private boolean _warnOnce;
private List _pendingRequests = new ArrayList<>();
private long _nextRetry;
}
private class LookupReplyI implements LookupReply
{
LookupReplyI(LocatorI locator)
{
_locator = locator;
}
@Override
public void foundLocator(com.zeroc.Ice.LocatorPrx locator, com.zeroc.Ice.Current curr)
{
_locator.foundLocator(locator);
}
private final LocatorI _locator;
}
public PluginI(String name, com.zeroc.Ice.Communicator communicator)
{
_name = name;
_communicator = communicator;
}
@Override
public void initialize()
{
com.zeroc.Ice.Properties properties = _communicator.getProperties();
boolean ipv4 = properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0;
boolean preferIPv6 = properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0;
String address;
if(ipv4 && !preferIPv6)
{
address = properties.getPropertyWithDefault(_name + ".Address", "239.255.0.1");
}
else
{
address = properties.getPropertyWithDefault(_name + ".Address", "ff15::1");
}
int port = properties.getPropertyAsIntWithDefault(_name + ".Port", 4061);
String intf = properties.getProperty(_name + ".Interface");
String lookupEndpoints = properties.getProperty(_name + ".Lookup");
if(lookupEndpoints.isEmpty())
{
int protocol = ipv4 && !preferIPv6 ? Network.EnableIPv4 : Network.EnableIPv6;
java.util.List interfaces = Network.getInterfacesForMulticast(intf, protocol);
for(String p : interfaces)
{
if(p != interfaces.get(0))
{
lookupEndpoints += ":";
}
lookupEndpoints += "udp -h \"" + address + "\" -p " + port + " --interface \"" + p + "\"";
}
}
if(properties.getProperty(_name + ".Reply.Endpoints").isEmpty())
{
properties.setProperty(_name + ".Reply.Endpoints", "udp -h " + (intf.isEmpty() ? "*" : "\"" + intf + "\""));
}
if(properties.getProperty(_name + ".Locator.Endpoints").isEmpty())
{
properties.setProperty(_name + ".Locator.AdapterId", java.util.UUID.randomUUID().toString());
}
_replyAdapter = _communicator.createObjectAdapter(_name + ".Reply");
_locatorAdapter = _communicator.createObjectAdapter(_name + ".Locator");
// We don't want those adapters to be registered with the locator so clear their locator.
_replyAdapter.setLocator(null);
_locatorAdapter.setLocator(null);
com.zeroc.Ice.ObjectPrx lookupPrx =
_communicator.stringToProxy("IceLocatorDiscovery/Lookup -d:" + lookupEndpoints);
// No collocation optimization or router for the multicast proxy!
lookupPrx = lookupPrx.ice_collocationOptimized(false).ice_router(null);
com.zeroc.Ice.LocatorPrx voidLoc =
com.zeroc.Ice.LocatorPrx.uncheckedCast(_locatorAdapter.addWithUUID(new VoidLocatorI()));
String instanceName = properties.getProperty(_name + ".InstanceName");
com.zeroc.Ice.Identity id = new com.zeroc.Ice.Identity();
id.name = "Locator";
id.category = !instanceName.isEmpty() ? instanceName : java.util.UUID.randomUUID().toString();
_locator = new LocatorI(_name, LookupPrx.uncheckedCast(lookupPrx), properties, instanceName, voidLoc);
_defaultLocator = _communicator.getDefaultLocator();
_locatorPrx = com.zeroc.Ice.LocatorPrx.uncheckedCast(_locatorAdapter.add(_locator, id));
_communicator.setDefaultLocator(_locatorPrx);
com.zeroc.Ice.ObjectPrx lookupReply = _replyAdapter.addWithUUID(new LookupReplyI(_locator)).ice_datagram();
_locator.setLookupReply(LookupReplyPrx.uncheckedCast(lookupReply));
_replyAdapter.activate();
_locatorAdapter.activate();
}
@Override
public void destroy()
{
if(_replyAdapter != null)
{
_replyAdapter.destroy();
}
if(_locatorAdapter != null)
{
_locatorAdapter.destroy();
}
if(_communicator.getDefaultLocator().equals(_locatorPrx))
{
// Restore original default locator proxy, if the user didn't change it in the meantime
_communicator.setDefaultLocator(_defaultLocator);
}
}
public List
getLocators(String instanceName, int waitTime)
{
return _locator.getLocators(instanceName, waitTime);
}
private String _name;
private com.zeroc.Ice.Communicator _communicator;
private com.zeroc.Ice.ObjectAdapter _locatorAdapter;
private com.zeroc.Ice.ObjectAdapter _replyAdapter;
private LocatorI _locator;
private com.zeroc.Ice.LocatorPrx _locatorPrx;
private com.zeroc.Ice.LocatorPrx _defaultLocator;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy