Instance.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import com.zeroc.Ice.Instrumentation.CommunicatorObserver;
import com.zeroc.Ice.Instrumentation.ObserverUpdater;
import com.zeroc.Ice.Instrumentation.ThreadObserver;
import com.zeroc.Ice.Instrumentation.ThreadState;
import com.zeroc.Ice.SSL.EndpointFactoryI;
import com.zeroc.Ice.SSL.SSLEngine;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @hidden Public because it's used by SSL.
*/
public final class Instance {
private static class ThreadObserverHelper {
ThreadObserverHelper(String threadName) {
_threadName = threadName;
}
public synchronized void updateObserver(
CommunicatorObserver obsv) {
assert (obsv != null);
_observer =
obsv.getThreadObserver(
"Communicator", _threadName, ThreadState.ThreadStateIdle, _observer);
if (_observer != null) {
_observer.attach();
}
}
protected void beforeExecute() {
_threadObserver = _observer;
if (_threadObserver != null) {
_threadObserver.stateChanged(
ThreadState.ThreadStateIdle, ThreadState.ThreadStateInUseForOther);
}
}
protected void afterExecute() {
if (_threadObserver != null) {
_threadObserver.stateChanged(
ThreadState.ThreadStateInUseForOther, ThreadState.ThreadStateIdle);
_threadObserver = null;
}
}
private final String _threadName;
//
// We use a volatile to avoid synchronization when reading
// _observer. Reference assignment is atomic in Java so it
// also doesn't need to be synchronized.
//
private volatile ThreadObserver _observer;
private ThreadObserver _threadObserver;
}
private static class Timer extends ScheduledThreadPoolExecutor {
Timer(Properties props, String threadName) {
super(1, Util.createThreadFactory(props, threadName)); // Single thread executor
setRemoveOnCancelPolicy(true);
setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
_observerHelper = new ThreadObserverHelper(threadName);
}
public void updateObserver(CommunicatorObserver obsv) {
_observerHelper.updateObserver(obsv);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
_observerHelper.beforeExecute();
}
@Override
protected void afterExecute(Runnable t, Throwable e) {
_observerHelper.afterExecute();
}
private final ThreadObserverHelper _observerHelper;
}
private static class QueueExecutor extends ThreadPoolExecutor {
QueueExecutor(Properties props, String threadName) {
super(
1,
1,
0,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
Util.createThreadFactory(props, threadName));
_observerHelper = new ThreadObserverHelper(threadName);
}
public void updateObserver(CommunicatorObserver obsv) {
_observerHelper.updateObserver(obsv);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
_observerHelper.beforeExecute();
}
@Override
protected void afterExecute(Runnable t, Throwable e) {
_observerHelper.afterExecute();
}
public void destroy() throws InterruptedException {
shutdown();
while (!isTerminated()) {
// A very long time.
awaitTermination(100000, TimeUnit.SECONDS);
}
}
private final ThreadObserverHelper _observerHelper;
}
private class ObserverUpdaterI implements ObserverUpdater {
@Override
public void updateConnectionObservers() {
Instance.this.updateConnectionObservers();
}
@Override
public void updateThreadObservers() {
Instance.this.updateThreadObservers();
}
}
public InitializationData initializationData() {
//
// No check for destruction. It must be possible to access the initialization data after
// destruction.
//
// No mutex lock, immutable.
//
return _initData;
}
public TraceLevels traceLevels() {
// No mutex lock, immutable.
assert (_traceLevels != null);
return _traceLevels;
}
public DefaultsAndOverrides defaultsAndOverrides() {
// No mutex lock, immutable.
assert (_defaultsAndOverrides != null);
return _defaultsAndOverrides;
}
public synchronized RouterManager routerManager() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_routerManager != null);
return _routerManager;
}
public synchronized LocatorManager locatorManager() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_locatorManager != null);
return _locatorManager;
}
public synchronized ReferenceFactory referenceFactory() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_referenceFactory != null);
return _referenceFactory;
}
public synchronized OutgoingConnectionFactory outgoingConnectionFactory() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_outgoingConnectionFactory != null);
return _outgoingConnectionFactory;
}
public synchronized ObjectAdapterFactory objectAdapterFactory() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_objectAdapterFactory != null);
return _objectAdapterFactory;
}
public int protocolSupport() {
return _protocolSupport;
}
public boolean preferIPv6() {
return _preferIPv6;
}
public NetworkProxy networkProxy() {
return _networkProxy;
}
public synchronized ThreadPool clientThreadPool() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_clientThreadPool != null);
return _clientThreadPool;
}
public synchronized ThreadPool serverThreadPool() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
// Lazy initialization.
if (_serverThreadPool == null) {
if (_state == StateDestroyInProgress) {
throw new CommunicatorDestroyedException();
}
int timeout = _initData.properties.getIcePropertyAsInt("Ice.ServerIdleTime");
_serverThreadPool = new ThreadPool(this, "Ice.ThreadPool.Server", timeout);
}
return _serverThreadPool;
}
public synchronized EndpointHostResolver endpointHostResolver() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_endpointHostResolver != null);
return _endpointHostResolver;
}
public synchronized RetryQueue retryQueue() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_retryQueue != null);
return _retryQueue;
}
public int[] retryIntervals() {
// No mutex lock, we return a copy.
return _retryIntervals.clone();
}
public synchronized ScheduledExecutorService timer() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_timer != null);
return _timer;
}
synchronized EndpointFactoryManager endpointFactoryManager() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_endpointFactoryManager != null);
return _endpointFactoryManager;
}
public synchronized PluginManager pluginManager() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
assert (_pluginManager != null);
return _pluginManager;
}
public int messageSizeMax() {
// No mutex lock, immutable.
return _messageSizeMax;
}
public int batchAutoFlushSize() {
// No mutex lock, immutable.
return _batchAutoFlushSize;
}
public int classGraphDepthMax() {
// No mutex lock, immutable.
return _classGraphDepthMax;
}
public ToStringMode toStringMode() {
// No mutex lock, immutable
return _toStringMode;
}
public int cacheMessageBuffers() {
// No mutex lock, immutable.
return _cacheMessageBuffers;
}
public ImplicitContextI getImplicitContext() {
return _implicitContext;
}
public synchronized ObjectPrx createAdmin(ObjectAdapter adminAdapter, Identity adminIdentity) {
boolean createAdapter = adminAdapter == null;
synchronized (this) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
if (adminIdentity == null
|| adminIdentity.name == null
|| adminIdentity.name.isEmpty()) {
throw new IllegalArgumentException(
"The admin identity '" + adminIdentity + "' is not valid");
}
if (_adminAdapter != null) {
throw new InitializationException("Admin already created");
}
if (!_adminEnabled) {
throw new InitializationException("Admin is disabled");
}
if (createAdapter) {
if (!_initData.properties.getIceProperty("Ice.Admin.Endpoints").isEmpty()) {
adminAdapter =
_objectAdapterFactory.createObjectAdapter("Ice.Admin", null, null);
} else {
throw new InitializationException("Ice.Admin.Endpoints is not set");
}
}
_adminIdentity = adminIdentity;
_adminAdapter = adminAdapter;
addAllAdminFacets();
}
if (createAdapter) {
try {
adminAdapter.activate();
} catch (LocalException ex) {
//
// We cleanup _adminAdapter, however this error is not recoverable
// (can't call again getAdmin() after fixing the problem)
// since all the facets (servants) in the adapter are lost
//
adminAdapter.destroy();
synchronized (this) {
_adminAdapter = null;
}
throw ex;
}
}
setServerProcessProxy(adminAdapter, adminIdentity);
return adminAdapter.createProxy(adminIdentity);
}
public ObjectPrx getAdmin() {
ObjectAdapter adminAdapter;
Identity adminIdentity;
synchronized (this) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
if (_adminAdapter != null) {
return _adminAdapter.createProxy(_adminIdentity);
} else if (_adminEnabled) {
if (!_initData.properties.getIceProperty("Ice.Admin.Endpoints").isEmpty()) {
adminAdapter =
_objectAdapterFactory.createObjectAdapter("Ice.Admin", null, null);
} else {
return null;
}
adminIdentity =
new Identity(
"admin",
_initData.properties.getIceProperty("Ice.Admin.InstanceName"));
if (adminIdentity.category.isEmpty()) {
adminIdentity.category = UUID.randomUUID().toString();
}
_adminIdentity = adminIdentity;
_adminAdapter = adminAdapter;
addAllAdminFacets();
// continue below outside synchronization
} else {
return null;
}
}
try {
adminAdapter.activate();
} catch (LocalException ex) {
//
// We cleanup _adminAdapter, however this error is not recoverable
// (can't call again getAdmin() after fixing the problem)
// since all the facets (servants) in the adapter are lost
//
adminAdapter.destroy();
synchronized (this) {
_adminAdapter = null;
}
throw ex;
}
setServerProcessProxy(adminAdapter, adminIdentity);
return adminAdapter.createProxy(adminIdentity);
}
public synchronized void addAdminFacet(Object servant, String facet) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
if (_adminAdapter == null
|| (!_adminFacetFilter.isEmpty() && !_adminFacetFilter.contains(facet))) {
if (_adminFacets.get(facet) != null) {
throw new AlreadyRegisteredException("facet", facet);
}
_adminFacets.put(facet, servant);
} else {
_adminAdapter.addFacet(servant, _adminIdentity, facet);
}
}
public synchronized Object removeAdminFacet(String facet) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
Object result;
if (_adminAdapter == null
|| (!_adminFacetFilter.isEmpty() && !_adminFacetFilter.contains(facet))) {
result = _adminFacets.remove(facet);
if (result == null) {
throw new NotRegisteredException("facet", facet);
}
} else {
result = _adminAdapter.removeFacet(_adminIdentity, facet);
}
return result;
}
public synchronized Object findAdminFacet(String facet) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
Object result = null;
if (_adminAdapter == null
|| (!_adminFacetFilter.isEmpty() && !_adminFacetFilter.contains(facet))) {
result = _adminFacets.get(facet);
} else {
result = _adminAdapter.findFacet(_adminIdentity, facet);
}
return result;
}
public synchronized Map<String, Object> findAllAdminFacets() {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
if (_adminAdapter == null) {
return new HashMap<>(_adminFacets);
} else {
Map<String, Object> result = _adminAdapter.findAllFacets(_adminIdentity);
if (!_adminFacets.isEmpty()) {
// Also returns filtered facets
result.putAll(_adminFacets);
}
return result;
}
}
public synchronized void setDefaultLocator(LocatorPrx locator) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
_referenceFactory = _referenceFactory.setDefaultLocator(locator);
}
public synchronized void setDefaultRouter(RouterPrx router) {
if (_state == StateDestroyed) {
throw new CommunicatorDestroyedException();
}
_referenceFactory = _referenceFactory.setDefaultRouter(router);
}
public void setLogger(Logger logger) {
//
// No locking, as it can only be called during plug-in loading
//
_initData.logger = logger;
}
public void setThreadHooks(Runnable threadStart, Runnable threadStop) {
//
// No locking, as it can only be called during plug-in loading
//
_initData.threadStart = threadStart;
_initData.threadStop = threadStop;
}
void addSliceLoader(SliceLoader loader) {
_applicationSliceLoader.add(loader);
}
Class<?> findClass(String className) {
return Util.findClass(className, _initData.classLoader);
}
// Only for use by com.zeroc.Ice.Communicator. If the application provides an initData, the initData argument is a
// clone.
void initialize(Communicator communicator, InitializationData initData) {
_state = StateActive;
_initData = initData;
try {
if (_initData.properties == null) {
_initData.properties = new Properties();
}
Properties properties = _initData.properties;
synchronized (Instance.class) {
if (!_oneOffDone) {
String stdOut = properties.getIceProperty("Ice.StdOut");
String stdErr = properties.getIceProperty("Ice.StdErr");
PrintStream outStream = null;
if (!stdOut.isEmpty()) {
//
// We need to close the existing stdout for JVM thread dump to go to the new
// file
//
System.out.close();
try {
outStream =
new PrintStream(
new FileOutputStream(stdOut, true));
} catch (FileNotFoundException ex) {
throw new FileException("cannot append to '" + stdOut + "'", ex);
}
System.setOut(outStream);
}
if (!stdErr.isEmpty()) {
//
// close for consistency with stdout
//
System.err.close();
if (stdErr.equals(stdOut)) {
System.setErr(outStream);
} else {
try {
System.setErr(
new PrintStream(
new FileOutputStream(stdErr, true)));
} catch (FileNotFoundException ex) {
throw new FileException("cannot append to '" + stdErr + "'", ex);
}
}
}
_oneOffDone = true;
}
}
if (_initData.logger == null) {
String logFile = properties.getIceProperty("Ice.LogFile");
if (properties.getIcePropertyAsInt("Ice.UseSyslog") > 0
&& !System.getProperty("os.name").startsWith("Windows")) {
if (!logFile.isEmpty()) {
throw new InitializationException(
"Both syslog and file logger cannot be enabled.");
}
_initData.logger =
new SysLoggerI(
properties.getIceProperty("Ice.ProgramName"),
properties.getIceProperty("Ice.SyslogFacility"),
properties.getIceProperty("Ice.SyslogHost"),
properties.getIcePropertyAsInt("Ice.SyslogPort"));
} else if (!logFile.isEmpty()) {
_initData.logger =
new FileLoggerI(properties.getIceProperty("Ice.ProgramName"), logFile);
} else {
_initData.logger = Util.getProcessLogger();
if (_initData.logger instanceof LoggerI) {
_initData.logger =
new LoggerI(properties.getIceProperty("Ice.ProgramName"));
}
}
}
validatePackages();
_traceLevels = new TraceLevels(properties);
_defaultsAndOverrides = new DefaultsAndOverrides(properties);
_clientConnectionOptions = readConnectionOptions("Ice.Connection.Client");
_serverConnectionOptions = readConnectionOptions("Ice.Connection.Server");
// The maximum size of an Ice protocol message in bytes. This is limited to 0x7fffffff, which corresponds to
// the maximum value of a 32-bit signed integer (int).
final int messageSizeMaxUpperLimit = Integer.MAX_VALUE;
int messageSizeMax = properties.getIcePropertyAsInt("Ice.MessageSizeMax");
if (messageSizeMax > messageSizeMaxUpperLimit / 1024) {
throw new InitializationException(
"Ice.MessageSizeMax '" + messageSizeMax + "' is too large, it must be less than or equal to '" + (messageSizeMaxUpperLimit / 1024) + "' KiB");
} else if (messageSizeMax < 1) {
_messageSizeMax = messageSizeMaxUpperLimit;
} else {
// The property is specified in kibibytes (KiB); _messageSizeMax is stored in bytes.
_messageSizeMax = messageSizeMax * 1024;
}
int batchAutoFlushSize = properties.getIcePropertyAsInt("Ice.BatchAutoFlushSize");
if (batchAutoFlushSize > messageSizeMaxUpperLimit / 1024) {
throw new InitializationException(
"Ice.BatchAutoFlushSize '" + batchAutoFlushSize + "' is too large, it must be less than or equal to '" + (messageSizeMaxUpperLimit / 1024) + "' KiB");
} else if (batchAutoFlushSize < 1) {
_batchAutoFlushSize = messageSizeMaxUpperLimit;
} else {
// The property is specified in kibibytes (KiB); _batchAutoFlushSize is stored in bytes.
_batchAutoFlushSize = batchAutoFlushSize * 1024;
}
int classGraphDepthMax = properties.getIcePropertyAsInt("Ice.ClassGraphDepthMax");
if (classGraphDepthMax < 1) {
_classGraphDepthMax = 0x7fffffff;
} else {
_classGraphDepthMax = classGraphDepthMax;
}
// Update _initData.sliceLoader.
if (_initData.sliceLoader != null) {
_applicationSliceLoader.add(_initData.sliceLoader);
}
var sliceLoader = new CompositeSliceLoader(_applicationSliceLoader);
// Ice.Package.module loader.
String packagePrefix = "Ice.Package";
Map<String, String> moduleDict = properties.getPropertiesForPrefix(packagePrefix);
if (!moduleDict.isEmpty()) {
Map<String, String> moduleToPackageMap = new HashMap<>();
for (Map.Entry<String, String> entry : moduleDict.entrySet()) {
String moduleName = entry.getKey().substring(packagePrefix.length() + 1); // top-level module
moduleToPackageMap.put("::" + moduleName, entry.getValue() + "." + moduleName);
}
sliceLoader.add(new ModuleToPackageSliceLoader(moduleToPackageMap, _initData.classLoader));
}
// Default package loader.
String defaultPackage = properties.getIceProperty("Ice.Default.Package");
if (!defaultPackage.isEmpty()) {
sliceLoader.add(new DefaultPackageSliceLoader(defaultPackage, _initData.classLoader));
}
// Built-in modules loader.
var builtInModulesLoader = new ModuleToPackageSliceLoader(
Map.of(
"::Glacier2", "com.zeroc.Glacier2",
"::Ice", "com.zeroc.Ice",
"::IceMX", "com.zeroc.IceMX",
"::IceBox", "com.zeroc.IceBox",
"::IceGrid", "com.zeroc.IceGrid",
"::IceStorm", "com.zeroc.IceStorm"),
_initData.classLoader);
// We decorate builtInModulesLoader because we don't want to map ::Ice::Object to com.zeroc.Ice.Object.
sliceLoader.add(typeId -> {
if ("::Ice::Object".equals(typeId)) {
return null;
} else {
return builtInModulesLoader.newInstance(typeId);
}
});
// Empty package prefix: module ::VisitorCenter maps to package VisitorCenter.
sliceLoader.add(new DefaultPackageSliceLoader("", _initData.classLoader));
// Finally add decorator that caches NotFound, if needed.
final int notFoundCacheSize =
properties.getIcePropertyAsInt("Ice.SliceLoader.NotFoundCacheSize");
if (notFoundCacheSize <= 0) {
_initData.sliceLoader = sliceLoader;
} else {
final Logger cacheFullLogger =
properties.getIcePropertyAsInt("Ice.Warn.SliceLoader") > 0 ? _initData.logger : null;
_initData.sliceLoader = new NotFoundSliceLoaderDecorator(
sliceLoader,
notFoundCacheSize,
cacheFullLogger);
}
String toStringModeStr = properties.getIceProperty("Ice.ToStringMode");
if ("Unicode".equals(toStringModeStr)) {
_toStringMode = ToStringMode.Unicode;
} else if ("ASCII".equals(toStringModeStr)) {
_toStringMode = ToStringMode.ASCII;
} else if ("Compat".equals(toStringModeStr)) {
_toStringMode = ToStringMode.Compat;
} else {
throw new InitializationException(
"The value for Ice.ToStringMode must be Unicode, ASCII or Compat");
}
_implicitContext =
ImplicitContextI.create(properties.getIceProperty("Ice.ImplicitContext"));
_routerManager = new RouterManager();
_locatorManager = new LocatorManager(properties);
_referenceFactory = new ReferenceFactory(this, communicator);
boolean isIPv6Supported = Network.isIPv6Supported();
boolean ipv4 = properties.getIcePropertyAsInt("Ice.IPv4") > 0;
boolean ipv6 = isIPv6Supported ? properties.getIcePropertyAsInt("Ice.IPv6") > 0 : false;
if (!ipv4 && !ipv6) {
throw new InitializationException("Both IPV4 and IPv6 support cannot be disabled.");
} else if (ipv4 && ipv6) {
_protocolSupport = Network.EnableBoth;
} else if (ipv4) {
_protocolSupport = Network.EnableIPv4;
} else {
_protocolSupport = Network.EnableIPv6;
}
_preferIPv6 = properties.getIcePropertyAsInt("Ice.PreferIPv6Address") > 0;
_networkProxy = createNetworkProxy(properties, _protocolSupport);
_sslEngine = new SSLEngine(communicator);
_endpointFactoryManager = new EndpointFactoryManager(this);
ProtocolInstance tcpProtocol =
new ProtocolInstance(this, TCPEndpointType.value, "tcp", false);
_endpointFactoryManager.add(new TcpEndpointFactory(tcpProtocol));
ProtocolInstance udpProtocol =
new ProtocolInstance(this, UDPEndpointType.value, "udp", false);
_endpointFactoryManager.add(new UdpEndpointFactory(udpProtocol));
com.zeroc.Ice.SSL.Instance sslInstance =
new com.zeroc.Ice.SSL.Instance(_sslEngine, SSLEndpointType.value, "ssl");
_endpointFactoryManager.add(
new EndpointFactoryI(sslInstance, TCPEndpointType.value));
ProtocolInstance wsProtocol =
new ProtocolInstance(this, WSEndpointType.value, "ws", false);
_endpointFactoryManager.add(new WSEndpointFactory(wsProtocol, TCPEndpointType.value));
ProtocolInstance wssProtocol =
new ProtocolInstance(this, WSSEndpointType.value, "wss", true);
_endpointFactoryManager.add(new WSEndpointFactory(wssProtocol, SSLEndpointType.value));
_pluginManager = new PluginManagerI(communicator, this);
_outgoingConnectionFactory = new OutgoingConnectionFactory(communicator, this);
_objectAdapterFactory = new ObjectAdapterFactory(this, communicator);
_retryQueue = new RetryQueue(this);
String[] arr = properties.getIcePropertyAsList("Ice.RetryIntervals");
if (arr.length == 0) {
_retryIntervals = new int[]{0};
} else {
_retryIntervals = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
int v;
try {
v = Integer.parseInt(arr[i]);
} catch (NumberFormatException ex) {
v = 0;
}
// If -1 is the first value, no retry and wait intervals.
if (i == 0 && v == -1) {
_retryIntervals = new int[0];
break;
}
_retryIntervals[i] = v > 0 ? v : 0;
}
}
_cacheMessageBuffers = properties.getIcePropertyAsInt("Ice.CacheMessageBuffers");
} catch (Exception ex) {
destroy(false);
throw ex;
}
}
@SuppressWarnings({"nofinalizer", "deprecation"})
@Override
protected synchronized void finalize() throws Throwable {
try {
Assert.FinalizerAssert(_state == StateDestroyed);
Assert.FinalizerAssert(_referenceFactory == null);
Assert.FinalizerAssert(_outgoingConnectionFactory == null);
Assert.FinalizerAssert(_objectAdapterFactory == null);
Assert.FinalizerAssert(_clientThreadPool == null);
Assert.FinalizerAssert(_serverThreadPool == null);
Assert.FinalizerAssert(_endpointHostResolver == null);
Assert.FinalizerAssert(_timer == null);
Assert.FinalizerAssert(_routerManager == null);
Assert.FinalizerAssert(_locatorManager == null);
Assert.FinalizerAssert(_endpointFactoryManager == null);
Assert.FinalizerAssert(_pluginManager == null);
Assert.FinalizerAssert(_retryQueue == null);
} catch (Exception ex) {} finally {
super.finalize();
}
}
void finishSetup(Communicator communicator) {
Properties properties = _initData.properties;
//
// Load plug-ins.
//
assert (_serverThreadPool == null);
PluginManagerI pluginManagerImpl = (PluginManagerI) _pluginManager;
pluginManagerImpl.loadPlugins();
//
// Initialize the endpoint factories once all the plugins are loaded. This gives
// the opportunity for the endpoint factories to find underlying factories.
//
_endpointFactoryManager.initialize();
//
// Create Admin facets, if enabled.
//
// Note that any logger-dependent admin facet must be created after we load all plugins,
// since one of these plugins can be a Logger plugin that sets a new logger during loading
//
if (properties.getIceProperty("Ice.Admin.Enabled").isEmpty()) {
_adminEnabled = !properties.getIceProperty("Ice.Admin.Endpoints").isEmpty();
} else {
_adminEnabled = properties.getIcePropertyAsInt("Ice.Admin.Enabled") > 0;
}
String[] facetFilter = properties.getIcePropertyAsList("Ice.Admin.Facets");
if (facetFilter.length > 0) {
_adminFacetFilter.addAll(Arrays.asList(facetFilter));
}
if (_adminEnabled) {
//
// Process facet
//
String processFacetName = "Process";
if (_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(processFacetName)) {
_adminFacets.put(processFacetName, new ProcessI(communicator));
}
//
// Logger facet
//
String loggerFacetName = "Logger";
if (_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(loggerFacetName)) {
LoggerAdminLogger logger = new LoggerAdminLoggerI(properties, _initData.logger);
setLogger(logger);
_adminFacets.put(loggerFacetName, logger.getFacet());
}
//
// Properties facet
//
String propertiesFacetName = "Properties";
NativePropertiesAdmin propsAdmin = null;
if (_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(propertiesFacetName)) {
propsAdmin = new NativePropertiesAdmin(this);
_adminFacets.put(propertiesFacetName, propsAdmin);
}
//
// Metrics facet
//
String metricsFacetName = "Metrics";
if (_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(metricsFacetName)) {
CommunicatorObserverI observer = new CommunicatorObserverI(_initData);
_initData.observer = observer;
_adminFacets.put(metricsFacetName, observer.getFacet());
//
// Make sure the admin plugin receives property updates.
//
if (propsAdmin != null) {
propsAdmin.addUpdateCallback(observer.getFacet());
}
}
}
//
// Set observer updater
//
if (_initData.observer != null) {
_initData.observer.setObserverUpdater(new ObserverUpdaterI());
}
//
// Create threads.
//
try {
_timer = new Timer(properties, Util.createThreadName(properties, "Ice.Timer"));
} catch (RuntimeException ex) {
String s = "cannot create thread for timer:\n" + Ex.toString(ex);
_initData.logger.error(s);
throw ex;
}
try {
_endpointHostResolver = new EndpointHostResolver(this);
} catch (RuntimeException ex) {
String s = "cannot create thread for endpoint host resolver:\n" + Ex.toString(ex);
_initData.logger.error(s);
throw ex;
}
_clientThreadPool = new ThreadPool(this, "Ice.ThreadPool.Client", 0);
//
// The default router/locator may have been set during the loading of plugins. Therefore we
// make sure it is not already set before checking the property.
//
if (_referenceFactory.getDefaultRouter() == null) {
RouterPrx router =
RouterPrx.uncheckedCast(communicator.propertyToProxy("Ice.Default.Router"));
if (router != null) {
_referenceFactory = _referenceFactory.setDefaultRouter(router);
}
}
if (_referenceFactory.getDefaultLocator() == null) {
LocatorPrx loc =
LocatorPrx.uncheckedCast(communicator.propertyToProxy("Ice.Default.Locator"));
if (loc != null) {
_referenceFactory = _referenceFactory.setDefaultLocator(loc);
}
}
// SslEngine initialization
_sslEngine.initialize();
//
// Server thread pool initialization is lazy in serverThreadPool().
//
//
// An application can set Ice.InitPlugins=0 if it wants to postpone
// initialization until after it has interacted directly with the
// plug-ins.
//
if (properties.getIcePropertyAsInt("Ice.InitPlugins") > 0) {
pluginManagerImpl.initializePlugins();
}
//
// This must be done last as this call creates the Ice.Admin object adapter
// and eventually registers a process proxy with the Ice locator (allowing
// remote clients to invoke on Ice.Admin facets as soon as it's registered).
//
if (properties.getIcePropertyAsInt("Ice.Admin.DelayCreation") <= 0) {
getAdmin();
}
}
//
// Only for use by com.zeroc.Ice.Communicator
//
void destroy(boolean interruptible) {
synchronized (this) {
//
// If destroy is in progress, wait for it to be done. This
// is necessary in case destroy() is called concurrently
// by multiple threads.
//
while (_state == StateDestroyInProgress) {
try {
wait();
} catch (InterruptedException ex) {
if (interruptible) {
throw new OperationInterruptedException(ex);
}
}
}
if (_state == StateDestroyed) {
return;
}
_state = StateDestroyInProgress;
}
try {
//
// Shutdown and destroy all the incoming and outgoing Ice connections and wait for the
// connections to be finished.
//
if (_objectAdapterFactory != null) {
_objectAdapterFactory.shutdown();
}
if (_outgoingConnectionFactory != null) {
_outgoingConnectionFactory.destroy();
}
if (_objectAdapterFactory != null) {
_objectAdapterFactory.destroy();
}
if (_outgoingConnectionFactory != null) {
_outgoingConnectionFactory.waitUntilFinished();
}
if (_retryQueue != null) {
_retryQueue.destroy(); // Must be called before destroying thread pools.
}
if (_initData.observer != null) {
_initData.observer.setObserverUpdater(null);
}
if (_initData.logger instanceof LoggerAdminLogger) {
// This only disables the remote logging; we don't set or reset _initData.logger
((LoggerAdminLogger) _initData.logger).destroy();
}
//
// Now, destroy the thread pools. This must be done *only* after all the connections are
// finished (the connections destruction can require invoking callbacks with the thread
// pools).
//
if (_serverThreadPool != null) {
_serverThreadPool.destroy();
}
if (_clientThreadPool != null) {
_clientThreadPool.destroy();
}
if (_endpointHostResolver != null) {
_endpointHostResolver.destroy();
}
if (_timer != null) {
_timer.shutdown(); // Don't use shutdownNow(), timers don't support interrupts
}
//
// Wait for all the threads to be finished.
//
try {
if (_clientThreadPool != null) {
_clientThreadPool.joinWithAllThreads();
}
if (_serverThreadPool != null) {
_serverThreadPool.joinWithAllThreads();
}
if (_endpointHostResolver != null) {
_endpointHostResolver.joinWithThread();
}
if (_timer != null) {
while (!_timer.isTerminated()) {
// A very long time.
_timer.awaitTermination(100000, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
if (interruptible) {
throw new OperationInterruptedException(ex);
}
}
//
// NOTE: at this point destroy() can't be interrupted
// anymore. The calls below are therefore guaranteed to be called once.
//
if (_routerManager != null) {
_routerManager.destroy();
}
if (_locatorManager != null) {
_locatorManager.destroy();
}
if (_initData.properties.getIcePropertyAsInt("Ice.Warn.UnusedProperties") > 0) {
List<String> unusedProperties =
_initData.properties.getUnusedProperties();
if (!unusedProperties.isEmpty()) {
StringBuilder message =
new StringBuilder("The following properties were set but never read:");
for (String p : unusedProperties) {
message.append("\n ");
message.append(p);
}
_initData.logger.warning(message.toString());
}
}
//
// Destroy last so that a Logger plugin can receive all log/traces before its
// destruction.
//
if (_pluginManager != null) {
_pluginManager.destroy();
}
if (_initData.logger instanceof FileLoggerI) {
FileLoggerI logger = (FileLoggerI) _initData.logger;
logger.destroy();
}
if (_initData.logger instanceof SysLoggerI) {
SysLoggerI logger = (SysLoggerI) _initData.logger;
logger.destroy();
}
synchronized (this) {
_objectAdapterFactory = null;
_outgoingConnectionFactory = null;
_retryQueue = null;
_serverThreadPool = null;
_clientThreadPool = null;
_endpointHostResolver = null;
_timer = null;
_referenceFactory = null;
_routerManager = null;
_locatorManager = null;
_endpointFactoryManager = null;
_pluginManager = null;
_adminAdapter = null;
_adminFacets.clear();
_state = StateDestroyed;
notifyAll();
}
} finally {
synchronized (this) {
if (_state == StateDestroyInProgress) {
assert interruptible;
_state = StateActive;
notifyAll();
}
}
}
}
public BufSizeWarnInfo getBufSizeWarn(short type) {
synchronized (_setBufSizeWarn) {
BufSizeWarnInfo info;
if (!_setBufSizeWarn.containsKey(type)) {
info = new BufSizeWarnInfo();
info.sndWarn = false;
info.sndSize = -1;
info.rcvWarn = false;
info.rcvSize = -1;
_setBufSizeWarn.put(type, info);
} else {
info = _setBufSizeWarn.get(type);
}
return info;
}
}
public void setSndBufSizeWarn(short type, int size) {
synchronized (_setBufSizeWarn) {
BufSizeWarnInfo info = getBufSizeWarn(type);
info.sndWarn = true;
info.sndSize = size;
_setBufSizeWarn.put(type, info);
}
}
public void setRcvBufSizeWarn(short type, int size) {
synchronized (_setBufSizeWarn) {
BufSizeWarnInfo info = getBufSizeWarn(type);
info.rcvWarn = true;
info.rcvSize = size;
_setBufSizeWarn.put(type, info);
}
}
SliceLoader sliceLoader() {
return _initData.sliceLoader;
}
ConnectionOptions clientConnectionOptions() {
return _clientConnectionOptions;
}
ConnectionOptions serverConnectionOptions(String adapterName) {
assert (!adapterName.isEmpty());
Properties properties = _initData.properties;
String propertyPrefix = adapterName + ".Connection";
return new ConnectionOptions(
properties.getPropertyAsIntWithDefault(
propertyPrefix + ".ConnectTimeout",
_serverConnectionOptions.connectTimeout()),
properties.getPropertyAsIntWithDefault(
propertyPrefix + ".CloseTimeout", _serverConnectionOptions.closeTimeout()),
properties.getPropertyAsIntWithDefault(
propertyPrefix + ".IdleTimeout", _serverConnectionOptions.idleTimeout()),
properties.getPropertyAsIntWithDefault(
propertyPrefix + ".EnableIdleCheck",
_serverConnectionOptions.enableIdleCheck() ? 1 : 0)
> 0,
properties.getPropertyAsIntWithDefault(
propertyPrefix + ".InactivityTimeout",
_serverConnectionOptions.inactivityTimeout()),
properties.getPropertyAsIntWithDefault(
propertyPrefix + ".MaxDispatches",
_serverConnectionOptions.maxDispatches()));
}
private void updateConnectionObservers() {
try {
assert (_outgoingConnectionFactory != null);
_outgoingConnectionFactory.updateConnectionObservers();
assert (_objectAdapterFactory != null);
_objectAdapterFactory.updateConnectionObservers();
} catch (CommunicatorDestroyedException ex) {}
}
private void updateThreadObservers() {
try {
if (_clientThreadPool != null) {
_clientThreadPool.updateObservers();
}
if (_serverThreadPool != null) {
_serverThreadPool.updateObservers();
}
assert (_objectAdapterFactory != null);
_objectAdapterFactory.updateThreadObservers();
if (_endpointHostResolver != null) {
_endpointHostResolver.updateObserver();
}
if (_timer != null) {
_timer.updateObserver(_initData.observer);
}
} catch (CommunicatorDestroyedException ex) {}
}
// TODO: should we drop this method together with the _Marker classes?
private void validatePackages() {
final String prefix = "Ice.Package.";
Map<String, String> map = _initData.properties.getPropertiesForPrefix(prefix);
for (Map.Entry<String, String> p : map.entrySet()) {
String key = p.getKey();
String pkg = p.getValue();
if (key.length() == prefix.length()) {
_initData.logger.warning("ignoring invalid property: " + key + "=" + pkg);
}
String module = key.substring(prefix.length());
String className = pkg + "." + module + "._Marker";
Class<?> cls = null;
try {
cls = findClass(className);
} catch (Exception ex) {}
if (cls == null) {
_initData.logger.warning("unable to validate package: " + key + "=" + pkg);
}
}
}
private synchronized void addAllAdminFacets() {
Map<String, Object> filteredFacets = new HashMap<>();
for (Map.Entry<String, Object> p : _adminFacets.entrySet()) {
if (_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(p.getKey())) {
_adminAdapter.addFacet(p.getValue(), _adminIdentity, p.getKey());
} else {
filteredFacets.put(p.getKey(), p.getValue());
}
}
_adminFacets = filteredFacets;
}
private void setServerProcessProxy(ObjectAdapter adminAdapter, Identity adminIdentity) {
ObjectPrx admin = adminAdapter.createProxy(adminIdentity);
LocatorPrx locator = adminAdapter.getLocator();
String serverId = _initData.properties.getIceProperty("Ice.Admin.ServerId");
if (locator != null && !serverId.isEmpty()) {
ProcessPrx process = ProcessPrx.uncheckedCast(admin.ice_facet("Process"));
try {
//
// Note that as soon as the process proxy is registered, the communicator might be
// shutdown by a remote client and admin facets might start receiving calls.
//
locator.getRegistry().setServerProcessProxy(serverId, process);
} catch (ServerNotFoundException ex) {
if (_traceLevels.location >= 1) {
StringBuilder s = new StringBuilder(128);
s.append("couldn't register server `");
s.append(serverId);
s.append("' with the locator registry:\n");
s.append("the server is not known to the locator registry");
_initData.logger.trace(_traceLevels.locationCat, s.toString());
}
throw new InitializationException(
"Locator knows nothing about server `" + serverId + "'");
} catch (LocalException ex) {
if (_traceLevels.location >= 1) {
StringBuilder s = new StringBuilder(128);
s.append("couldn't register server `");
s.append(serverId);
s.append("' with the locator registry:\n");
s.append(ex.toString());
_initData.logger.trace(_traceLevels.locationCat, s.toString());
}
throw ex;
}
if (_traceLevels.location >= 1) {
StringBuilder s = new StringBuilder(128);
s.append("registered server `");
s.append(serverId);
s.append("' with the locator registry");
_initData.logger.trace(_traceLevels.locationCat, s.toString());
}
}
}
private NetworkProxy createNetworkProxy(Properties properties, int protocolSupport) {
String proxyHost;
proxyHost = properties.getIceProperty("Ice.SOCKSProxyHost");
if (!proxyHost.isEmpty()) {
if (protocolSupport == Network.EnableIPv6) {
throw new InitializationException("IPv6 only is not supported with SOCKS4 proxies");
}
int proxyPort = properties.getIcePropertyAsInt("Ice.SOCKSProxyPort");
return new SOCKSNetworkProxy(proxyHost, proxyPort);
}
proxyHost = properties.getIceProperty("Ice.HTTPProxyHost");
if (!proxyHost.isEmpty()) {
return new HTTPNetworkProxy(
proxyHost, properties.getIcePropertyAsInt("Ice.HTTPProxyPort"));
}
return null;
}
private ConnectionOptions readConnectionOptions(String propertyPrefix) {
Properties properties = _initData.properties;
return new ConnectionOptions(
properties.getIcePropertyAsInt(propertyPrefix + ".ConnectTimeout"),
properties.getIcePropertyAsInt(propertyPrefix + ".CloseTimeout"),
properties.getIcePropertyAsInt(propertyPrefix + ".IdleTimeout"),
properties.getIcePropertyAsInt(propertyPrefix + ".EnableIdleCheck") > 0,
properties.getIcePropertyAsInt(propertyPrefix + ".InactivityTimeout"),
properties.getIcePropertyAsInt(propertyPrefix + ".MaxDispatches"));
}
private static final int StateActive = 0;
private static final int StateDestroyInProgress = 1;
private static final int StateDestroyed = 2;
private int _state;
private InitializationData _initData; // Immutable, not reset by destroy().
private TraceLevels _traceLevels; // Immutable, not reset by destroy().
private DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy().
private int _messageSizeMax; // Immutable, not reset by destroy().
private int _batchAutoFlushSize; // Immutable, not reset by destroy().
private int _classGraphDepthMax; // Immutable, not reset by destroy().
private SliceLoader _sliceLoader; // Immutable, not reset by destroy().
private ToStringMode _toStringMode; // Immutable, not reset by destroy().
private int _cacheMessageBuffers; // Immutable, not reset by destroy().
private ImplicitContextI _implicitContext;
private RouterManager _routerManager;
private LocatorManager _locatorManager;
private ReferenceFactory _referenceFactory;
private OutgoingConnectionFactory _outgoingConnectionFactory;
private ObjectAdapterFactory _objectAdapterFactory;
private int _protocolSupport;
private boolean _preferIPv6;
private NetworkProxy _networkProxy;
private ThreadPool _clientThreadPool;
private ThreadPool _serverThreadPool;
private EndpointHostResolver _endpointHostResolver;
private RetryQueue _retryQueue;
private int[] _retryIntervals;
private Timer _timer;
private EndpointFactoryManager _endpointFactoryManager;
private PluginManager _pluginManager;
private boolean _adminEnabled;
private ObjectAdapter _adminAdapter;
private Map<String, Object> _adminFacets = new HashMap<>();
private final Set<String> _adminFacetFilter = new HashSet<>();
private Identity _adminIdentity;
private final Map<Short, BufSizeWarnInfo> _setBufSizeWarn = new HashMap<>();
private static boolean _oneOffDone;
private SSLEngine _sslEngine;
private ConnectionOptions _clientConnectionOptions;
private ConnectionOptions _serverConnectionOptions;
// The Slice loader(s) added by the application: initData.sliceLoader followed by the loaders added by
// addSliceLoader.
private final CompositeSliceLoader _applicationSliceLoader = new CompositeSliceLoader();
}