ServiceManagerI.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.IceBox;
import com.zeroc.Ice.Communicator;
import com.zeroc.Ice.CommunicatorDestroyedException;
import com.zeroc.Ice.Current;
import com.zeroc.Ice.InitializationData;
import com.zeroc.Ice.LocalException;
import com.zeroc.Ice.Logger;
import com.zeroc.Ice.Object;
import com.zeroc.Ice.ObjectAdapterDeactivatedException;
import com.zeroc.Ice.ObjectAdapterDestroyedException;
import com.zeroc.Ice.Options;
import com.zeroc.Ice.ParseException;
import com.zeroc.Ice.Properties;
import com.zeroc.Ice.Util;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
final class ServiceManagerI implements ServiceManager {
public ServiceManagerI(Communicator communicator, String[] args) {
_communicator = communicator;
_logger = _communicator.getLogger();
Properties props = _communicator.getProperties();
if (props.getIceProperty("Ice.Admin.Enabled").isEmpty()) {
_adminEnabled = !props.getIceProperty("Ice.Admin.Endpoints").isEmpty();
} else {
_adminEnabled = props.getIcePropertyAsInt("Ice.Admin.Enabled") > 0;
}
if (_adminEnabled) {
String[] facetFilter = props.getIcePropertyAsList("Ice.Admin.Facets");
if (facetFilter.length > 0) {
_adminFacetFilter = new HashSet<>(Arrays.asList(facetFilter));
} else {
_adminFacetFilter = new HashSet<>();
}
}
_argv = args;
_traceServiceObserver = props.getIcePropertyAsInt("IceBox.Trace.ServiceObserver");
}
@Override
public void startService(String name, Current current)
throws AlreadyStartedException, NoSuchServiceException {
ServiceInfo info = null;
synchronized (this) {
// Search would be more efficient if services were contained in a map, but order is
// required for shutdown.
for (ServiceInfo p : _services) {
if (p.name.equals(name)) {
if (p.status == StatusStarted) {
throw new AlreadyStartedException();
}
p.status = StatusStarting;
info = p.clone();
break;
}
}
if (info == null) {
throw new NoSuchServiceException();
}
_pendingStatusChanges = true;
}
boolean started = false;
try {
info.service.start(
name,
info.communicator == null ? _sharedCommunicator : info.communicator,
info.args);
started = true;
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
_logger.warning(
"ServiceManager: exception while starting service "
+ info.name
+ ":\n"
+ sw.toString());
}
synchronized (this) {
for (ServiceInfo p : _services) {
if (p.name.equals(name)) {
if (started) {
p.status = StatusStarted;
List<String> services = new ArrayList<>();
services.add(name);
servicesStarted(services, _observers);
} else {
p.status = StatusStopped;
}
break;
}
}
_pendingStatusChanges = false;
notifyAll();
}
}
@Override
public void stopService(String name, Current current)
throws AlreadyStoppedException, NoSuchServiceException {
ServiceInfo info = null;
synchronized (this) {
// Search would be more efficient if services were contained in a map, but order is
// required for shutdown.
for (ServiceInfo p : _services) {
if (p.name.equals(name)) {
if (p.status == StatusStopped) {
throw new AlreadyStoppedException();
}
p.status = StatusStopping;
info = p.clone();
break;
}
}
if (info == null) {
throw new NoSuchServiceException();
}
_pendingStatusChanges = true;
}
boolean stopped = false;
try {
info.service.stop();
stopped = true;
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
_logger.warning(
"ServiceManager: exception while stopping service "
+ info.name
+ ":\n"
+ sw.toString());
}
synchronized (this) {
for (ServiceInfo p : _services) {
if (p.name.equals(name)) {
if (stopped) {
p.status = StatusStopped;
List<String> services = new ArrayList<>();
services.add(name);
servicesStopped(services, _observers);
} else {
p.status = StatusStarted;
}
break;
}
}
_pendingStatusChanges = false;
notifyAll();
}
}
@Override
public void addObserver(final ServiceObserverPrx observer, Current current) {
List<String> activeServices = new LinkedList<>();
// Null observers and duplicate registrations are ignored
synchronized (this) {
if (observer != null && _observers.add(observer)) {
if (_traceServiceObserver >= 1) {
_logger.trace(
"IceBox.ServiceObserver",
"Added service observer " + _communicator.proxyToString(observer));
}
for (ServiceInfo info : _services) {
if (info.status == StatusStarted) {
activeServices.add(info.name);
}
}
}
}
if (!activeServices.isEmpty()) {
observer.servicesStartedAsync(activeServices.toArray(new String[0]))
.exceptionally(
ex -> {
observerFailed(observer, ex);
return null;
});
}
}
@Override
public void shutdown(Current current) {
_communicator.shutdown();
}
public int run() {
try {
Properties properties = _communicator.getProperties();
// Parse the property set with the prefix "IceBox.Service.". These
// properties should have the following format:
//
// IceBox.Service.Foo=[jar-or-dir:]Package.Foo [args]
//
// We parse the service properties specified in IceBox.LoadOrder first, then the ones
// from remaining services.
final String prefix = "IceBox.Service.";
Map<String, String> services = properties.getPropertiesForPrefix(prefix);
if (services.isEmpty()) {
throw new FailureException(
"ServiceManager: configuration must include at least one IceBox service");
}
String[] loadOrder = properties.getIcePropertyAsList("IceBox.LoadOrder");
List<StartServiceInfo> servicesInfo = new ArrayList<>();
for (String name : loadOrder) {
if (!name.isEmpty()) {
String key = prefix + name;
String value = services.get(key);
if (value == null) {
throw new FailureException(
"ServiceManager: no service definition for `" + name + "'");
}
servicesInfo.add(new StartServiceInfo(name, value, _argv));
services.remove(key);
}
}
for (Map.Entry<String, String> p : services.entrySet()) {
String name = p.getKey().substring(prefix.length());
String value = p.getValue();
servicesInfo.add(new StartServiceInfo(name, value, _argv));
}
// Check if some services are using the shared communicator in which case we create the
// shared communicator now with a property set that is the union of all the service
// properties (from services that use the shared communicator).
if (properties.getPropertiesForPrefix("IceBox.UseSharedCommunicator.").size() > 0) {
InitializationData initData = new InitializationData();
initData.properties = createServiceProperties("SharedCommunicator");
for (StartServiceInfo service : servicesInfo) {
if (properties.getIcePropertyAsInt(
"IceBox.UseSharedCommunicator." + service.name)
<= 0) {
continue;
}
// Load the service properties using the shared communicator properties as the
// default properties.
List<String> remainingArgs = new ArrayList<>();
Properties serviceProps =
new Properties(service.args, initData.properties, remainingArgs);
service.args = remainingArgs.toArray(new String[remainingArgs.size()]);
// Remove properties from the shared property set that a service explicitly
// clears.
Map<String, String> allProps =
initData.properties.getPropertiesForPrefix("");
for (String key : allProps.keySet()) {
if (serviceProps.getProperty(key).isEmpty()) {
initData.properties.setProperty(key, "");
}
}
// Add the service properties to the shared communicator properties.
for (Map.Entry<String, String> p :
serviceProps.getPropertiesForPrefix("").entrySet()) {
initData.properties.setProperty(p.getKey(), p.getValue());
}
// Parse <service>.* command line options (the Ice command line options
// were parsed by the call to createProperties above).
service.args =
initData.properties.parseCommandLineOptions(service.name, service.args);
}
String facetNamePrefix = "IceBox.SharedCommunicator.";
boolean addFacets = configureAdmin(initData.properties, facetNamePrefix);
_sharedCommunicator = Util.initialize(initData);
if (addFacets) {
// Add all facets created on shared communicator to the IceBox communicator but
// renamed <prefix>.<facet-name>, except for the Process facet which is never
// added.
for (Map.Entry<String, Object> p :
_sharedCommunicator.findAllAdminFacets().entrySet()) {
if (!"Process".equals(p.getKey())) {
_communicator.addAdminFacet(p.getValue(), facetNamePrefix + p.getKey());
}
}
}
}
for (StartServiceInfo s : servicesInfo) {
start(s.name, s.className, s.classDir, s.absolutePath, s.args);
}
// Start Admin (if enabled).
_communicator.addAdminFacet(this, "IceBox.ServiceManager");
_communicator.getAdmin();
// We may want to notify external scripts that the services have started and that IceBox
// is "ready".
// This is done by defining the property IceBox.PrintServicesReady=bundleName
//
// bundleName is whatever you choose to call this set of services. It will be echoed
// back as "bundleName ready".
//
// This must be done after start() has been invoked on the services.
String bundleName = properties.getIceProperty("IceBox.PrintServicesReady");
if (!bundleName.isEmpty()) {
System.out.println(bundleName + " ready");
}
_communicator.waitForShutdown();
} catch (FailureException ex) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println(ex.toString());
ex.printStackTrace(pw);
pw.flush();
_logger.error(sw.toString());
return 1;
} catch (CommunicatorDestroyedException ex) {
// Expected if the communicator is shutdown by the shutdown hook
} catch (ObjectAdapterDeactivatedException ex) {
// Expected if the communicator is shutdown by the shutdown hook
} catch (ObjectAdapterDestroyedException ex) {
// Expected
} catch (Throwable ex) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
pw.flush();
_logger.error("ServiceManager: caught exception:\n" + sw.toString());
return 1;
} finally {
// Invoke stop() on the services.
stopAll();
}
return 0;
}
private synchronized void start(
String service, String className, String classDir, boolean absolutePath, String[] args)
throws FailureException {
// Load the class.
// Use a class loader if the user specified a JAR file or class directory.
Class<?> c = null;
if (classDir != null) {
try {
if (!absolutePath) {
classDir =
new File(
System.getProperty("user.dir")
+ File.separator
+ classDir)
.getCanonicalPath();
}
if (!classDir.endsWith(File.separator) && !classDir.endsWith(".jar")) {
classDir += File.separator;
}
classDir = URLEncoder.encode(classDir, "UTF-8");
// Reuse an existing class loader if we have already loaded a plug-in with the same
// value for classDir, otherwise create a new one.
ClassLoader cl = null;
if (_classLoaders == null) {
_classLoaders = new HashMap<>();
} else {
cl = _classLoaders.get(classDir);
}
if (cl == null) {
final URL[] url =
new URL[]{new URL("file:///" + classDir)};
cl = new URLClassLoader(url);
_classLoaders.put(classDir, cl);
}
c = cl.loadClass(className);
} catch (MalformedURLException ex) {
throw new FailureException(
"ServiceManager: invalid entry point format `" + classDir + "'", ex);
} catch (IOException ex) {
throw new FailureException(
"ServiceManager: invalid path in plug-in entry point `" + classDir + "'",
ex);
} catch (ClassNotFoundException ex) {
// Ignored
}
} else {
c = Util.findClass(className, null);
}
if (c == null) {
throw new FailureException("ServiceManager: class " + className + " not found");
}
ServiceInfo info = new ServiceInfo();
info.name = service;
info.status = StatusStopped;
info.args = args;
// If IceBox.UseSharedCommunicator.<name> is defined, create a
// communicator for the service. The communicator inherits from the shared communicator
// properties. If it's not defined, add the service properties to the shared communicator
// property set.
Communicator communicator;
if (_communicator
.getProperties()
.getIcePropertyAsInt("IceBox.UseSharedCommunicator." + service)
> 0) {
assert (_sharedCommunicator != null);
communicator = _sharedCommunicator;
} else {
try {
// Create the service properties. We use the communicator properties as the default
// properties if IceBox.InheritProperties is set.
InitializationData initData = new InitializationData();
initData.properties = createServiceProperties(service);
String[] serviceArgs = info.args;
if (serviceArgs.length > 0) {
// Create the service properties with the given service arguments. This should
// read the service config file if it's specified with --Ice.Config.
List<String> remainingArgs = new ArrayList<>();
initData.properties =
new Properties(serviceArgs, initData.properties, remainingArgs);
serviceArgs = remainingArgs.toArray(new String[remainingArgs.size()]);
// Next, parse the service "<service>.*" command line options (the Ice command
// line options were parsed by the createProperties above).
serviceArgs = initData.properties.parseCommandLineOptions(service, serviceArgs);
info.args = serviceArgs;
}
// Clone the logger to assign a new prefix. If one of the built-in loggers is
// configured don't set any logger.
if (initData.properties.getIceProperty("Ice.LogFile").isEmpty()
&& (initData.properties.getIcePropertyAsInt("Ice.UseSyslog") <= 0
|| System.getProperty("os.name").startsWith("Windows"))) {
initData.logger =
_logger.cloneWithPrefix(
initData.properties.getIceProperty("Ice.ProgramName"));
}
// If Admin is enabled on the IceBox communicator, for each service that does not
// set
// Ice.Admin.Enabled, we set Ice.Admin.Enabled=1 to have this service create facets;
// then
// we add these facets to the IceBox Admin object as
// IceBox.Service.<service>.<facet>.
String serviceFacetNamePrefix = "IceBox.Service." + service + ".";
boolean addFacets = configureAdmin(initData.properties, serviceFacetNamePrefix);
info.communicator = Util.initialize(initData);
communicator = info.communicator;
if (addFacets) {
// Add all facets created on the service communicator to the IceBox communicator
// but renamed IceBox.Service.<service>.<facet-name>, except for the Process
// facet which is never added
for (Map.Entry<String, Object> p :
communicator.findAllAdminFacets().entrySet()) {
if (!"Process".equals(p.getKey())) {
_communicator.addAdminFacet(
p.getValue(), serviceFacetNamePrefix + p.getKey());
}
}
}
} catch (Throwable ex) {
throw new FailureException(
"ServiceManager: exception while starting service " + service, ex);
}
}
try {
// Instantiate the service.
try {
// If the service class provides a constructor that accepts an
// com.zeroc.Ice.Communicator argument,
// use that in preference to the default constructor.
java.lang.Object obj = null;
try {
java.lang.reflect.Constructor<?> con =
c.getDeclaredConstructor(Communicator.class);
obj = con.newInstance(_communicator);
} catch (IllegalAccessException ex) {
throw new FailureException(
"ServiceManager: unable to access service constructor "
+ className
+ "(com.zeroc.Ice.Communicator)",
ex);
} catch (NoSuchMethodException ex) {
// Ignore.
} catch (java.lang.reflect.InvocationTargetException ex) {
if (ex.getCause() != null) {
throw ex.getCause();
} else {
throw new FailureException(
"ServiceManager: exception in service constructor for " + className,
ex);
}
}
if (obj == null) {
// Fall back to the default constructor.
try {
obj = c.getDeclaredConstructor().newInstance();
} catch (IllegalAccessException ex) {
throw new FailureException(
"ServiceManager: unable to access default service constructor in"
+ " class "
+ className,
ex);
}
}
try {
info.service = (Service) obj;
} catch (ClassCastException ex) {
throw new FailureException(
"ServiceManager: class "
+ className
+ " does not implement com.zeroc.IceBox.Service");
}
} catch (InstantiationException ex) {
throw new FailureException(
"ServiceManager: unable to instantiate class " + className, ex);
} catch (FailureException ex) {
throw ex;
} catch (Throwable ex) {
throw new FailureException(
"ServiceManager: exception in service constructor for " + className, ex);
}
try {
info.service.start(service, communicator, info.args);
// There is no need to notify the observers since the 'start all'
// (that indirectly calls this method) occurs before the creation of
// the Server Admin object, and before the activation of the main
// object adapter (so before any observer can be registered)
} catch (FailureException ex) {
throw ex;
} catch (Throwable ex) {
throw new FailureException(
"ServiceManager: exception while starting service " + service, ex);
}
info.status = StatusStarted;
_services.add(info);
} catch (RuntimeException ex) {
if (info.communicator != null) {
destroyServiceCommunicator(service, info.communicator);
}
throw ex;
}
}
private synchronized void stopAll() {
// First wait for any active startService/stopService calls to complete.
while (_pendingStatusChanges) {
try {
wait();
} catch (InterruptedException ex) {}
}
// For each service, we call stop on the service.
// Services are stopped in the reverse order of the order they were started.
List<String> stoppedServices = new ArrayList<>();
ListIterator<ServiceInfo> p = _services.listIterator(_services.size());
while (p.hasPrevious()) {
ServiceInfo info = p.previous();
if (info.status == StatusStarted) {
try {
info.service.stop();
info.status = StatusStopped;
stoppedServices.add(info.name);
} catch (Throwable e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
_logger.warning(
"ServiceManager: exception while stopping service "
+ info.name
+ ":\n"
+ sw.toString());
}
}
if (info.communicator != null) {
destroyServiceCommunicator(info.name, info.communicator);
}
}
if (_sharedCommunicator != null) {
removeAdminFacets("IceBox.SharedCommunicator.");
try {
_sharedCommunicator.destroy();
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
_logger.warning(
"ServiceManager: exception while destroying shared communicator:\n"
+ sw.toString());
}
_sharedCommunicator = null;
}
_services.clear();
servicesStopped(stoppedServices, _observers);
}
private void servicesStarted(
List<String> services, Set<ServiceObserverPrx> observers) {
if (!services.isEmpty()) {
String[] servicesArray = services.toArray(new String[0]);
for (final ServiceObserverPrx observer : observers) {
observer.servicesStartedAsync(servicesArray)
.exceptionally(
ex -> {
observerFailed(observer, ex);
return null;
});
}
}
}
private void servicesStopped(
List<String> services, Set<ServiceObserverPrx> observers) {
if (!services.isEmpty()) {
String[] servicesArray = services.toArray(new String[0]);
for (final ServiceObserverPrx observer : observers) {
observer.servicesStoppedAsync(servicesArray)
.exceptionally(
ex -> {
observerFailed(observer, ex);
return null;
});
}
}
}
private synchronized void observerFailed(ServiceObserverPrx observer, Throwable ex) {
if (ex instanceof LocalException) {
if (_observers.remove(observer)) {
observerRemoved(observer, (LocalException) ex);
}
}
}
private void observerRemoved(ServiceObserverPrx observer, RuntimeException ex) {
if (_traceServiceObserver >= 1) {
// CommunicatorDestroyedException may occur during shutdown. The observer notification
// has been sent, but the communicator was destroyed before the reply was received. We
// do not log a message for this exception.
if (!(ex instanceof CommunicatorDestroyedException)) {
_logger.trace(
"IceBox.ServiceObserver",
"Removed service observer "
+ _communicator.proxyToString(observer)
+ "\nafter catching "
+ ex.toString());
}
}
}
public static final int StatusStopping = 0;
public static final int StatusStopped = 1;
public static final int StatusStarting = 2;
public static final int StatusStarted = 3;
static final class ServiceInfo implements Cloneable {
@Override
public ServiceInfo clone() {
ServiceInfo c = null;
try {
c = (ServiceInfo) super.clone();
} catch (CloneNotSupportedException ex) {}
return c;
}
public String name;
public Service service;
public Communicator communicator;
public int status;
public String[] args;
}
static class StartServiceInfo {
StartServiceInfo(String service, String value, String[] serverArgs) {
name = service;
// We support the following formats:
//
// <class-name> [args]
// <jar-file>:<class-name> [args]
// <class-dir>:<class-name> [args]
// "<path with spaces>":<class-name> [args]
// "<path with spaces>:<class-name>" [args]
try {
args = Options.split(value);
} catch (ParseException ex) {
throw new FailureException(
"ServiceManager: invalid arguments for service `" + name + "'", ex);
}
assert (args.length > 0);
final String entryPoint = args[0];
final boolean isWindows = System.getProperty("os.name").startsWith("Windows");
absolutePath = false;
// Find first ':' that isn't part of the file path.
int pos = entryPoint.indexOf(':');
if (isWindows) {
final String driveLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (pos == 1
&& entryPoint.length() > 2
&& driveLetters.indexOf(entryPoint.charAt(0)) != -1
&& (entryPoint.charAt(2) == '\\' || entryPoint.charAt(2) == '/')) {
absolutePath = true;
pos = entryPoint.indexOf(':', pos + 1);
}
if (!absolutePath) {
absolutePath = entryPoint.startsWith("\\\\");
}
} else {
absolutePath = entryPoint.startsWith("/");
}
if ((pos == -1 && absolutePath) || (pos != -1 && entryPoint.length() <= pos + 1)) {
// Class name is missing.
throw new FailureException(
"ServiceManager: invalid entry point for service `"
+ name
+ "':\n"
+ entryPoint);
}
// Extract the JAR file or subdirectory, if any.
classDir = null; // Path name of JAR file or subdirectory.
if (pos == -1) {
className = entryPoint;
} else {
classDir = entryPoint.substring(0, pos).trim();
className = entryPoint.substring(pos + 1).trim();
}
// Shift the arguments.
String[] tmp = new String[args.length - 1];
System.arraycopy(args, 1, tmp, 0, args.length - 1);
args = tmp;
if (serverArgs.length > 0) {
List<String> l = new ArrayList<>(Arrays.asList(args));
for (String arg : serverArgs) {
if (arg.startsWith("--" + service + ".")) {
l.add(arg);
}
}
args = l.toArray(args);
}
}
String name;
String[] args;
String className;
String classDir;
boolean absolutePath;
}
private Properties createServiceProperties(String service) {
Properties properties = new Properties();
Properties communicatorProperties = _communicator.getProperties();
if (communicatorProperties.getIcePropertyAsInt("IceBox.InheritProperties") > 0) {
// Inherit all except IceBox. and Ice.Admin. properties
for (Map.Entry<String, String> p :
communicatorProperties.getPropertiesForPrefix("").entrySet()) {
String key = p.getKey();
if (!key.startsWith("IceBox.") && !key.startsWith("Ice.Admin.")) {
properties.setProperty(key, p.getValue());
}
}
}
String programName = communicatorProperties.getIceProperty("Ice.ProgramName");
if (programName.isEmpty()) {
properties.setProperty("Ice.ProgramName", service);
} else {
properties.setProperty("Ice.ProgramName", programName + "-" + service);
}
return properties;
}
private void destroyServiceCommunicator(
String service, Communicator communicator) {
try {
communicator.shutdown();
communicator.waitForShutdown();
} catch (CommunicatorDestroyedException e) {
// Ignore, the service might have already destroyed the communicator for its own
// reasons.
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
_logger.warning(
"ServiceManager: exception in shutting down communicator for service "
+ service
+ "\n"
+ sw.toString());
}
removeAdminFacets("IceBox.Service." + service + ".");
communicator.destroy();
}
private boolean configureAdmin(Properties properties, String prefix) {
if (_adminEnabled && properties.getIceProperty("Ice.Admin.Enabled").isEmpty()) {
List<String> facetNames = new LinkedList<>();
for (String p : _adminFacetFilter) {
if (p.startsWith(prefix)) {
facetNames.add(p.substring(prefix.length()));
}
}
if (_adminFacetFilter.isEmpty() || !facetNames.isEmpty()) {
properties.setProperty("Ice.Admin.Enabled", "1");
if (!facetNames.isEmpty()) {
// TODO: need join with escape!
properties.setProperty("Ice.Admin.Facets", String.join(" ", facetNames));
}
return true;
}
}
return false;
}
private void removeAdminFacets(String prefix) {
try {
for (String p : _communicator.findAllAdminFacets().keySet()) {
if (p.startsWith(prefix)) {
_communicator.removeAdminFacet(p);
}
}
} catch (CommunicatorDestroyedException ex) {
// Ignored
} catch (ObjectAdapterDeactivatedException ex) {
// Ignored
} catch (ObjectAdapterDestroyedException ex) {
// Ignored
}
}
private final Communicator _communicator;
private boolean _adminEnabled;
private Set<String> _adminFacetFilter;
private Communicator _sharedCommunicator;
private final Logger _logger;
private final String[] _argv; // Filtered server argument vector
private final List<ServiceInfo> _services = new LinkedList<>();
private boolean _pendingStatusChanges;
private final HashSet<ServiceObserverPrx> _observers = new HashSet<>();
private final int _traceServiceObserver;
private Map<String, ClassLoader> _classLoaders;
}