You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ja...@apache.org on 2013/11/11 13:15:32 UTC

svn commit: r1540691 - in /felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal: JettyConfig.java JettyService.java

Author: jawi
Date: Mon Nov 11 12:15:31 2013
New Revision: 1540691

URL: http://svn.apache.org/r1540691
Log:
FELIX-4312 - avoid pointless service interruptions:

- when the configuration of the HTTP Jetty service isn't changed,
  do not restart the server;
- avoid visibility of partial configurations during an update of the
  configuration.


Modified:
    felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyConfig.java
    felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java

Modified: felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyConfig.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyConfig.java?rev=1540691&r1=1540690&r2=1540691&view=diff
==============================================================================
--- felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyConfig.java (original)
+++ felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyConfig.java Mon Nov 11 12:15:31 2013
@@ -19,11 +19,8 @@ package org.apache.felix.http.jetty.inte
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
-import java.util.Map;
 import java.util.Properties;
 
 import org.osgi.framework.BundleContext;
@@ -83,13 +80,13 @@ public final class JettyConfig
     /** Felix specific property to configure the session timeout in minutes (same session-timout in web.xml). Default is servlet container specific */
     public static final String FELIX_SESSION_TIMEOUT = "org.apache.felix.http.session.timeout";
 
-    /** Felix speicific property to configure the request buffer size. Default is 16KB (instead of Jetty's default of 4KB) */
+    /** Felix specific property to configure the request buffer size. Default is 16KB (instead of Jetty's default of 4KB) */
     public static final String FELIX_JETTY_HEADER_BUFFER_SIZE = "org.apache.felix.http.jetty.headerBufferSize";
 
-    /** Felix speicific property to configure the request buffer size. Default is 8KB */
+    /** Felix specific property to configure the request buffer size. Default is 8KB */
     public static final String FELIX_JETTY_REQUEST_BUFFER_SIZE = "org.apache.felix.http.jetty.requestBufferSize";
 
-    /** Felix speicific property to configure the request buffer size. Default is 24KB */
+    /** Felix specific property to configure the request buffer size. Default is 24KB */
     public static final String FELIX_JETTY_RESPONSE_BUFFER_SIZE = "org.apache.felix.http.jetty.responseBufferSize";
 
     /** Felix specific property to enable Jetty MBeans. Valid values are "true", "false". Default is false */
@@ -101,28 +98,28 @@ public final class JettyConfig
     /** Felix specific property to set the list of path exclusions for Web Application Bundles */
     public static final String FELIX_HTTP_PATH_EXCLUSIONS = "org.apache.felix.http.path_exclusions";
 
+    private static String validateContextPath(String ctxPath)
+    {
+        // undefined, empty, or root context path
+        if (ctxPath == null || ctxPath.length() == 0 || "/".equals(ctxPath))
+        {
+            return "/";
+        }
+
+        // ensure leading but no trailing slash
+        if (!ctxPath.startsWith("/"))
+        {
+            ctxPath = "/".concat(ctxPath);
+        }
+        while (ctxPath.endsWith("/"))
+        {
+            ctxPath = ctxPath.substring(0, ctxPath.length() - 1);
+        }
+
+        return ctxPath;
+    }
+
     private final BundleContext context;
-    private boolean debug;
-    private String host;
-    private int httpPort;
-    private int httpsPort;
-    private int httpTimeout;
-    private String keystore;
-    private String password;
-    private String keyPassword;
-    private boolean useHttps;
-    private String truststore;
-    private String trustPassword;
-    private boolean useHttp;
-    private String clientcert;
-    private boolean useHttpNio;
-    private boolean useHttpsNio;
-    private boolean registerMBeans;
-    private int sessionTimeout;
-    private int requestBufferSize;
-    private int responseBufferSize;
-    private String contextPath;
-    private String[] pathExclusions;
 
     /**
      * Properties from the configuration not matching any of the
@@ -132,7 +129,7 @@ public final class JettyConfig
      * This map is indexed by String objects (the property names) and
      * the values are just objects as provided by the configuration.
      */
-    private Map genericProperties = new HashMap();
+    private volatile Dictionary config;
 
     public JettyConfig(BundleContext context)
     {
@@ -140,94 +137,114 @@ public final class JettyConfig
         reset();
     }
 
-    public boolean isDebug()
-    {
-        return this.debug;
-    }
-
     /**
-     * Returns <code>true</code> if HTTP is configured to be used (
-     * {@link #FELIX_HTTP_ENABLE}) and
-     * the configured HTTP port ({@link #HTTP_PORT}) is higher than zero.
+     * Returns the named generic configuration property from the
+     * configuration or the bundle context. If neither property is defined
+     * return the defValue.
      */
-    public boolean isUseHttp()
+    public boolean getBooleanProperty(String name, boolean defValue)
     {
-        return this.useHttp && getHttpPort() > 0;
+        String value = getProperty(name, null);
+        if (value != null)
+        {
+            return "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value);
+        }
+
+        return defValue;
     }
 
-    public boolean isUseHttpNio()
+    public String getClientcert()
     {
-        return this.useHttpNio;
+        return getProperty(FELIX_HTTPS_CLIENT_CERT, "none");
     }
 
-    /**
-     * Returns <code>true</code> if HTTPS is configured to be used (
-     * {@link #FELIX_HTTPS_ENABLE}) and
-     * the configured HTTP port ({@link #HTTPS_PORT}) is higher than zero.
-     */
-    public boolean isUseHttps()
+    public String getContextPath()
     {
-        return this.useHttps && getHttpsPort() > 0;
+        return validateContextPath(getProperty(FELIX_HTTP_CONTEXT_PATH, null));
     }
 
-    public boolean isUseHttpsNio()
+    public String getHost()
     {
-        return this.useHttpsNio;
+        return getProperty(FELIX_HOST, null);
     }
 
-    public boolean isRegisterMBeans()
+    public int getHttpPort()
     {
-        return this.registerMBeans;
+        return getIntProperty(HTTP_PORT, 8080);
     }
 
-    public String getHost()
+    public int getHttpsPort()
     {
-        return this.host;
+        return getIntProperty(HTTPS_PORT, 8443);
     }
 
-    public int getHttpPort()
+    public int getHttpTimeout()
     {
-        return this.httpPort;
+        return getIntProperty(HTTP_TIMEOUT, 60000);
     }
 
-    public int getHttpsPort()
+    /**
+     * Returns the named generic configuration property from the
+     * configuration or the bundle context. If neither property is defined
+     * return the defValue.
+     */
+    public int getIntProperty(String name, int defValue)
     {
-        return this.httpsPort;
+        try
+        {
+            return Integer.parseInt(getProperty(name, null));
+        }
+        catch (Exception e)
+        {
+            return defValue;
+        }
     }
 
-    public int getHttpTimeout()
+    public String getKeyPassword()
     {
-        return this.httpTimeout;
+        return getProperty(FELIX_KEYSTORE_KEY_PASSWORD, this.context.getProperty(OSCAR_KEYSTORE_KEY_PASSWORD));
     }
 
     public String getKeystore()
     {
-        return this.keystore;
+        return getProperty(FELIX_KEYSTORE, this.context.getProperty(OSCAR_KEYSTORE));
     }
 
     public String getPassword()
     {
-        return this.password;
+        return getProperty(FELIX_KEYSTORE_PASSWORD, this.context.getProperty(OSCAR_KEYSTORE_PASSWORD));
     }
 
-    public String getTruststore()
+    public String[] getPathExclusions()
     {
-        return this.truststore;
+        return getStringArrayProperty(FELIX_HTTP_PATH_EXCLUSIONS, new String[] { "/system" });
     }
 
-    public String getTrustPassword()
+    /**
+     * Returns the named generic configuration property from the
+     * configuration or the bundle context. If neither property is defined
+     * return the defValue.
+     */
+    public String getProperty(String name, String defValue)
     {
-        return this.trustPassword;
+        Dictionary conf = this.config;
+        Object value = (conf != null) ? conf.get(name) : null;
+        if (value == null)
+        {
+            value = this.context.getProperty(name);
+        }
+
+        return value != null ? String.valueOf(value) : defValue;
     }
 
-    public String getKeyPassword()
+    public int getRequestBufferSize()
     {
-        return this.keyPassword;
+        return getIntProperty(FELIX_JETTY_REQUEST_BUFFER_SIZE, 8 * 1024);
     }
 
-    public String getClientcert()
+    public int getResponseBufferSize()
     {
-        return this.clientcert;
+        return getIntProperty(FELIX_JETTY_RESPONSE_BUFFER_SIZE, 24 * 1024);
     }
 
     /**
@@ -236,109 +253,103 @@ public final class JettyConfig
      */
     public int getSessionTimeout()
     {
-        return this.sessionTimeout;
+        return getIntProperty(FELIX_SESSION_TIMEOUT, 0);
     }
 
-    public int getRequestBufferSize()
+    public String getTrustPassword()
     {
-        return this.requestBufferSize;
+        return getProperty(FELIX_TRUSTSTORE_PASSWORD, null);
     }
 
-    public int getResponseBufferSize()
+    public String getTruststore()
     {
-        return this.responseBufferSize;
+        return getProperty(FELIX_TRUSTSTORE, null);
     }
 
-    public String getContextPath()
+    public boolean isDebug()
     {
-        return contextPath;
+        return getBooleanProperty(FELIX_HTTP_DEBUG, getBooleanProperty(HTTP_DEBUG, false));
     }
 
-    public String[] getPathExclusions()
+    public boolean isRegisterMBeans()
     {
-        return this.pathExclusions;
+        return getBooleanProperty(FELIX_HTTP_MBEANS, false);
     }
 
-    public void reset()
+    /**
+     * Returns <code>true</code> if HTTP is configured to be used (
+     * {@link #FELIX_HTTP_ENABLE}) and
+     * the configured HTTP port ({@link #HTTP_PORT}) is higher than zero.
+     */
+    public boolean isUseHttp()
     {
-        update(null);
+        boolean useHttp = getBooleanProperty(FELIX_HTTP_ENABLE, true);
+        return useHttp && getHttpPort() > 0;
     }
 
-    public void update(Dictionary props)
+    public boolean isUseHttpNio()
     {
-        if (props == null)
-        {
-            props = new Properties();
-        }
-
-        this.debug = getBooleanProperty(props, FELIX_HTTP_DEBUG, getBooleanProperty(props, HTTP_DEBUG, false));
-        this.host = getProperty(props, FELIX_HOST, null);
-        this.httpPort = getIntProperty(props, HTTP_PORT, 8080);
-        this.httpsPort = getIntProperty(props, HTTPS_PORT, 8443);
-        this.httpTimeout = getIntProperty(props, HTTP_TIMEOUT, 60000);
-        this.keystore = getProperty(props, FELIX_KEYSTORE, this.context.getProperty(OSCAR_KEYSTORE));
-        this.password = getProperty(props, FELIX_KEYSTORE_PASSWORD, this.context.getProperty(OSCAR_KEYSTORE_PASSWORD));
-        this.keyPassword = getProperty(props, FELIX_KEYSTORE_KEY_PASSWORD, this.context.getProperty(OSCAR_KEYSTORE_KEY_PASSWORD));
-        this.useHttps = getBooleanProperty(props, FELIX_HTTPS_ENABLE, getBooleanProperty(props, OSCAR_HTTPS_ENABLE, false));
-        this.useHttp = getBooleanProperty(props, FELIX_HTTP_ENABLE, true);
-        this.truststore = getProperty(props, FELIX_TRUSTSTORE, null);
-        this.trustPassword = getProperty(props, FELIX_TRUSTSTORE_PASSWORD, null);
-        this.clientcert = getProperty(props, FELIX_HTTPS_CLIENT_CERT, "none");
-        this.useHttpNio = getBooleanProperty(props, FELIX_HTTP_NIO, true);
-        this.useHttpsNio = getBooleanProperty(props, FELIX_HTTPS_NIO, this.useHttpNio);
-        this.registerMBeans = getBooleanProperty(props, FELIX_HTTP_MBEANS, false);
-        this.sessionTimeout = getIntProperty(props, FELIX_SESSION_TIMEOUT, 0);
-        this.requestBufferSize = getIntProperty(FELIX_JETTY_REQUEST_BUFFER_SIZE, 8 * 1024);
-        this.responseBufferSize = getIntProperty(FELIX_JETTY_RESPONSE_BUFFER_SIZE, 24 * 1024);
-        this.contextPath = validateContextPath(getProperty(props, FELIX_HTTP_CONTEXT_PATH, null));
-        this.pathExclusions = getStringArrayProperty(props, FELIX_HTTP_PATH_EXCLUSIONS, new String[] { "/system" });
-
-        // copy rest of the properties
-        Enumeration keys = props.keys();
-        while (keys.hasMoreElements())
-        {
-            Object key = keys.nextElement();
-            this.genericProperties.put(key, props.get(key));
-        }
+        return getBooleanProperty(FELIX_HTTP_NIO, true);
     }
 
-    private String getProperty(Dictionary props, String name, String defValue)
+    /**
+     * Returns <code>true</code> if HTTPS is configured to be used (
+     * {@link #FELIX_HTTPS_ENABLE}) and
+     * the configured HTTP port ({@link #HTTPS_PORT}) is higher than zero.
+     */
+    public boolean isUseHttps()
     {
-        Object value = props.remove(name);
-        if (value == null)
-        {
-            value = this.context.getProperty(name);
-        }
+        boolean useHttps = getBooleanProperty(FELIX_HTTPS_ENABLE, getBooleanProperty(OSCAR_HTTPS_ENABLE, false));
+        return useHttps && getHttpsPort() > 0;
+    }
 
-        return value != null ? String.valueOf(value) : defValue;
+    public boolean isUseHttpsNio()
+    {
+        return getBooleanProperty(FELIX_HTTPS_NIO, isUseHttpNio());
     }
 
-    private boolean getBooleanProperty(Dictionary props, String name, boolean defValue)
+    public void reset()
     {
-        String value = getProperty(props, name, null);
-        if (value != null)
-        {
-            return (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"));
-        }
+        update(null);
+    }
 
-        return defValue;
+    public void setServiceProperties(Hashtable<String, Object> props)
+    {
+        props.put(HTTP_PORT, Integer.toString(getHttpPort()));
+        props.put(HTTPS_PORT, Integer.toString(getHttpsPort()));
+        props.put(FELIX_HTTP_ENABLE, Boolean.toString(isUseHttp()));
+        props.put(FELIX_HTTPS_ENABLE, Boolean.toString(isUseHttps()));
     }
 
-    private int getIntProperty(Dictionary props, String name, int defValue)
+    /**
+     * Updates this configuration with the given dictionary.
+     * 
+     * @param props the dictionary with the new configuration values, can be <code>null</code> to reset this configuration to its defaults.
+     * @return <code>true</code> if the configuration was updated due to a changed value, or <code>false</code> if no change was found.
+     */
+    public boolean update(Dictionary props)
     {
-        try
+        if (props == null)
         {
-            return Integer.parseInt(getProperty(props, name, null));
+            props = new Properties();
         }
-        catch (Exception e)
+
+        // FELIX-4312 Check whether there's something changed in our configuration... 
+        Dictionary currentConfig = this.config;
+        if (currentConfig == null || !props.equals(currentConfig))
         {
-            return defValue;
+            this.config = props;
+
+            return true;
         }
+
+        return false;
     }
 
-    private String[] getStringArrayProperty(Dictionary props, String name, String[] defValue)
+    private String[] getStringArrayProperty(String name, String[] defValue)
     {
-        Object value = props.remove(name);
+        Dictionary conf = this.config;
+        Object value = (conf != null) ? conf.get(name) : null;
         if (value == null)
         {
             value = this.context.getProperty(name);
@@ -369,82 +380,4 @@ public final class JettyConfig
             return defValue;
         }
     }
-
-    private static String validateContextPath(String ctxPath)
-    {
-        // undefined, empty, or root context path
-        if (ctxPath == null || ctxPath.length() == 0 || "/".equals(ctxPath))
-        {
-            return "/";
-        }
-
-        // ensure leading but no trailing slash
-        if (!ctxPath.startsWith("/"))
-        {
-            ctxPath = "/".concat(ctxPath);
-        }
-        while (ctxPath.endsWith("/"))
-        {
-            ctxPath = ctxPath.substring(0, ctxPath.length() - 1);
-        }
-
-        return ctxPath;
-    }
-
-    /**
-     * Returns the named generic configuration property from the
-     * configuration or the bundle context. If neither property is defined
-     * return the defValue.
-     */
-    public String getProperty(String name, String defValue)
-    {
-        Object value = this.genericProperties.get(name);
-        if (value == null)
-        {
-            value = this.context.getProperty(name);
-        }
-
-        return value != null ? String.valueOf(value) : defValue;
-    }
-
-    /**
-     * Returns the named generic configuration property from the
-     * configuration or the bundle context. If neither property is defined
-     * return the defValue.
-     */
-    public boolean getBooleanProperty(String name, boolean defValue)
-    {
-        String value = getProperty(name, null);
-        if (value != null)
-        {
-            return (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"));
-        }
-
-        return defValue;
-    }
-
-    /**
-     * Returns the named generic configuration property from the
-     * configuration or the bundle context. If neither property is defined
-     * return the defValue.
-     */
-    public int getIntProperty(String name, int defValue)
-    {
-        try
-        {
-            return Integer.parseInt(getProperty(name, null));
-        }
-        catch (Exception e)
-        {
-            return defValue;
-        }
-    }
-
-    public void setServiceProperties(Hashtable<String, Object> props)
-    {
-        props.put(HTTP_PORT, String.valueOf(this.httpPort));
-        props.put(HTTPS_PORT, String.valueOf(this.httpsPort));
-        props.put(FELIX_HTTP_ENABLE, String.valueOf(this.useHttp));
-        props.put(FELIX_HTTPS_ENABLE, String.valueOf(this.useHttps));
-    }
 }

Modified: felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java?rev=1540691&r1=1540690&r2=1540691&view=diff
==============================================================================
--- felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java (original)
+++ felix/trunk/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java Mon Nov 11 12:15:31 2013
@@ -59,6 +59,7 @@ import org.osgi.framework.BundleEvent;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.util.tracker.BundleTracker;
@@ -85,18 +86,19 @@ public final class JettyService extends 
 
     private final JettyConfig config;
     private final BundleContext context;
+    private final DispatcherServlet dispatcher;
+    private final HttpServiceController controller;
+    private final Map<String, Deployment> deployments;
+    private final ExecutorService executor;
+
     private ServiceRegistration configServiceReg;
-    private ExecutorService executor;
     private Server server;
     private ContextHandlerCollection parent;
-    private DispatcherServlet dispatcher;
     private EventDispatcher eventDispatcher;
-    private final HttpServiceController controller;
     private MBeanServerTracker mbeanServerTracker;
     private BundleTracker bundleTracker;
     private ServiceTracker serviceTracker;
     private EventAdmin eventAdmin;
-    private Map<String, Deployment> deployments = new LinkedHashMap<String, Deployment>();
 
     public JettyService(BundleContext context, DispatcherServlet dispatcher, EventDispatcher eventDispatcher, HttpServiceController controller)
     {
@@ -105,14 +107,7 @@ public final class JettyService extends 
         this.dispatcher = dispatcher;
         this.eventDispatcher = eventDispatcher;
         this.controller = controller;
-    }
-
-    public void start() throws Exception
-    {
-        Properties props = new Properties();
-        props.put(Constants.SERVICE_PID, PID);
-        this.configServiceReg = this.context.registerService("org.osgi.service.cm.ManagedService", new JettyManagedService(this), props);
-
+        this.deployments = new LinkedHashMap<String, Deployment>();
         this.executor = Executors.newSingleThreadExecutor(new ThreadFactory()
         {
             public Thread newThread(Runnable runnable)
@@ -122,6 +117,10 @@ public final class JettyService extends 
                 return t;
             }
         });
+    }
+
+    public void start() throws Exception
+    {
         this.executor.submit(new JettyOperation()
         {
             @Override
@@ -131,6 +130,10 @@ public final class JettyService extends 
             }
         });
 
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_PID, PID);
+        this.configServiceReg = this.context.registerService(ManagedService.class.getName(), new JettyManagedService(this), props);
+
         this.serviceTracker = new ServiceTracker(this.context, EventAdmin.class.getName(), this);
         this.serviceTracker.open();
 
@@ -140,46 +143,58 @@ public final class JettyService extends 
 
     public void stop() throws Exception
     {
-        if (this.executor != null && !this.executor.isShutdown())
-        {
-            this.executor.submit(new JettyOperation()
-            {
-                @Override
-                protected void doExecute() throws Exception
-                {
-                    stopJetty();
-                }
-            });
-            this.executor.shutdown();
-        }
         if (this.configServiceReg != null)
         {
             this.configServiceReg.unregister();
+            this.configServiceReg = null;
         }
         if (this.bundleTracker != null)
         {
             this.bundleTracker.close();
+            this.bundleTracker = null;
         }
         if (this.serviceTracker != null)
         {
             this.serviceTracker.close();
+            this.serviceTracker = null;
+        }
+
+        if (isExecutorServiceAvailable())
+        {
+            this.executor.submit(new JettyOperation()
+            {
+                @Override
+                protected void doExecute() throws Exception
+                {
+                    stopJetty();
+                }
+            });
+
+            this.executor.shutdown();
         }
     }
 
     private void publishServiceProperties()
     {
         Hashtable<String, Object> props = new Hashtable<String, Object>();
+        // Add some important configuration properties...
         this.config.setServiceProperties(props);
-        this.addEndpointProperties(props, null);
+        addEndpointProperties(props, null);
+
+        // propagate the new service properties to the actual HTTP service...
         this.controller.setProperties(props);
     }
 
     public void updated(Dictionary props)
     {
-        this.config.update(props);
-
-        if (this.executor != null && !this.executor.isShutdown())
+        if (isExecutorServiceAvailable())
         {
+            if (!this.config.update(props))
+            {
+                // Nothing changed in our configuration, let's not needlessly restart Jetty...
+                return;
+            }
+
             this.executor.submit(new JettyOperation()
             {
                 @Override
@@ -592,7 +607,7 @@ public final class JettyService extends 
 
     public void deploy(final Deployment deployment, final WebAppBundleContext context)
     {
-        if (this.executor != null && !this.executor.isShutdown())
+        if (isExecutorServiceAvailable())
         {
             this.executor.submit(new JettyOperation()
             {
@@ -631,7 +646,7 @@ public final class JettyService extends 
 
     public void undeploy(final Deployment deployment, final WebAppBundleContext context)
     {
-        if (this.executor != null && !this.executor.isShutdown())
+        if (isExecutorServiceAvailable())
         {
             this.executor.submit(new JettyOperation()
             {
@@ -831,4 +846,12 @@ public final class JettyService extends 
 
         protected abstract void doExecute() throws Exception;
     }
+
+    /**
+     * @return <code>true</code> if there is a valid executor service available, <code>false</code> otherwise.
+     */
+    private boolean isExecutorServiceAvailable()
+    {
+        return this.executor != null && !this.executor.isShutdown();
+    }
 }