X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=datarouter-node%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Fdmaap%2Fdatarouter%2Fnode%2FNodeConfigManager.java;h=2e2dc5f066aaf25d0c15333d44eba795c9d8eef0;hb=8b695ac559bda388781e5ad0e4b02d1e82dc9cef;hp=5b5245da76e8fe9cacb73193e428e81287bb58ad;hpb=a4c361637f3cf19b1c5fd4bdc55e40645e34505b;p=dmaap%2Fdatarouter.git diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java index 5b5245da..2e2dc5f0 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java @@ -25,6 +25,7 @@ package org.onap.dmaap.datarouter.node; import static java.lang.System.exit; +import static java.lang.System.getProperty; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; @@ -35,10 +36,17 @@ import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.nio.file.Files; +import java.util.HashSet; +import java.util.Iterator; import java.util.Objects; import java.util.Properties; import java.util.Timer; +import org.onap.dmaap.datarouter.node.config.NodeConfig; +import org.onap.dmaap.datarouter.node.config.ProvData; +import org.onap.dmaap.datarouter.node.delivery.DeliveryQueueHelper; import org.onap.dmaap.datarouter.node.eelf.EelfMsgs; +import org.onap.dmaap.datarouter.node.utils.NodeTlsManager; +import org.onap.dmaap.datarouter.node.utils.NodeUtils; /** @@ -54,10 +62,7 @@ import org.onap.dmaap.datarouter.node.eelf.EelfMsgs; public class NodeConfigManager implements DeliveryQueueHelper { private static final String NODE_CONFIG_MANAGER = "NodeConfigManager"; - private static EELFLogger eelfLogger = EELFManager.getInstance().getLogger(NodeConfigManager.class); - private static NodeConfigManager base = new NodeConfigManager(); - - private Timer timer = new Timer("Node Configuration Timer", true); + private static final EELFLogger eelfLogger = EELFManager.getInstance().getLogger(NodeConfigManager.class); private long maxfailuretimer; private long initfailuretimer; private long waitForFileProcessFailureTimer; @@ -68,83 +73,53 @@ public class NodeConfigManager implements DeliveryQueueHelper { private double fdpstart; private double fdpstop; private int deliverythreads; - private String provurl; + private final String provurl; private String provhost; - private IsFrom provcheck; - private int gfport; - private int svcport; - private int port; - private String spooldir; - private String logdir; - private long logretention; - private String redirfile; - private String kstype; - private String ksfile; - private String kspass; - private String kpass; - private String tstype; - private String tsfile; - private String tspass; + private final int intHttpPort; + private final int intHttpsPort; + private final int extHttpsPort; + private final boolean tlsEnabled; private String myname; - private RedirManager rdmgr; - private RateLimitedOperation pfetcher; - private NodeConfig config; - private File quiesce; - private PublishId pid; - private String nak; - private TaskList configtasks = new TaskList(); - private String eventlogurl; - private String eventlogprefix; - private String eventlogsuffix; + private final String nak; + private final File quiesce; + private final String spooldir; + private final String logdir; + private final long logretention; + private final String eventlogurl; + private final String eventlogprefix; + private final String eventlogsuffix; private String eventloginterval; private boolean followredirects; - private String[] enabledprotocols; - private String aafType; - private String aafInstance; - private String aafAction; - private boolean cadiEnabled; - private NodeAafPropsUtils nodeAafPropsUtils; - - + private final TaskList configtasks = new TaskList(); + private final PublishId publishId; + private final IsFrom provcheck; + private final RedirManager rdmgr; + private final Timer timer = new Timer("Node Configuration Timer", true); + private final RateLimitedOperation pfetcher; + private static NodeConfigManager base; + private static NodeTlsManager nodeTlsManager; + private NodeConfig nodeConfig; + private static Properties drNodeProperties; + + public static Properties getDrNodeProperties() { + if (drNodeProperties == null) { + try (FileInputStream props = new FileInputStream(getProperty( + "org.onap.dmaap.datarouter.node.properties", + "/opt/app/datartr/etc/node.properties"))) { + drNodeProperties = new Properties(); + drNodeProperties.load(props); + } catch (IOException e) { + eelfLogger.error("Failed to load NODE properties: " + e.getMessage(), e); + exit(1); + } + } + return drNodeProperties; + } /** * Initialize the configuration of a Data Router node. */ private NodeConfigManager() { - - Properties drNodeProperties = new Properties(); - try (FileInputStream fileInputStream = new FileInputStream(System - .getProperty("org.onap.dmaap.datarouter.node.properties", "/opt/app/datartr/etc/node.properties"))) { - eelfLogger.debug("NODE0301 Loading local config file node.properties"); - drNodeProperties.load(fileInputStream); - } catch (Exception e) { - NodeUtils.setIpAndFqdnForEelf(NODE_CONFIG_MANAGER); - eelfLogger.error(EelfMsgs.MESSAGE_PROPERTIES_LOAD_ERROR, e, - System.getProperty("org.onap.dmaap.datarouter.node.properties", - "/opt/app/datartr/etc/node.properties")); - } - provurl = drNodeProperties.getProperty("ProvisioningURL", "https://dmaap-dr-prov:8443/internal/prov"); - String aafPropsFilePath = drNodeProperties - .getProperty("AAFPropsFilePath", "/opt/app/osaaf/local/org.onap.dmaap-dr.props"); - try { - nodeAafPropsUtils = new NodeAafPropsUtils(new File(aafPropsFilePath)); - } catch (IOException e) { - eelfLogger.error("NODE0314 Failed to load AAF props. Exiting", e); - exit(1); - } - /* - * START - AAF changes: TDP EPIC US# 307413 - * Pull AAF settings from node.properties - */ - aafType = drNodeProperties.getProperty("AAFType", "org.onap.dmaap-dr.feed"); - aafInstance = drNodeProperties.getProperty("AAFInstance", "legacy"); - aafAction = drNodeProperties.getProperty("AAFAction", "publish"); - cadiEnabled = Boolean.parseBoolean(drNodeProperties.getProperty("CadiEnabled", "false")); - /* - * END - AAF changes: TDP EPIC US# 307413 - * Pull AAF settings from node.properties - */ - //Disable and enable protocols*/ - enabledprotocols = ((drNodeProperties.getProperty("NodeHttpsProtocols")).trim()).split("\\|"); + provurl = getDrNodeProperties().getProperty("ProvisioningURL", "http://dmaap-dr-prov:8080/internal/prov"); try { provhost = (new URL(provurl)).getHost(); } catch (Exception e) { @@ -152,13 +127,32 @@ public class NodeConfigManager implements DeliveryQueueHelper { eelfLogger.error(EelfMsgs.MESSAGE_BAD_PROV_URL, e, provurl); exit(1); } - eelfLogger.debug("NODE0303 Provisioning server is " + provhost); - eventlogurl = drNodeProperties.getProperty("LogUploadURL", "https://feeds-drtr.web.att.com/internal/logs"); + eelfLogger.debug("NODE0303 Provisioning server is at: " + provhost); provcheck = new IsFrom(provhost); - gfport = Integer.parseInt(drNodeProperties.getProperty("IntHttpPort", "8080")); - svcport = Integer.parseInt(drNodeProperties.getProperty("IntHttpsPort", "8443")); - port = Integer.parseInt(drNodeProperties.getProperty("ExtHttpsPort", "443")); - spooldir = drNodeProperties.getProperty("SpoolDir", "spool"); + tlsEnabled = Boolean.parseBoolean(getDrNodeProperties().getProperty("TlsEnabled", "true")); + if (isTlsEnabled()) { + try { + nodeTlsManager = new NodeTlsManager(getDrNodeProperties()); + myname = nodeTlsManager.getMyNameFromCertificate(); + if (myname == null) { + NodeUtils.setIpAndFqdnForEelf(NODE_CONFIG_MANAGER); + eelfLogger.error(EelfMsgs.MESSAGE_KEYSTORE_FETCH_ERROR, nodeTlsManager.getKeyStorefile()); + eelfLogger.error("NODE0309 Unable to fetch canonical name from keystore file {}", nodeTlsManager.getKeyStorefile()); + exit(1); + } + eelfLogger.debug("NODE0304 My certificate says my name is {}", myname); + } catch (Exception e) { + eelfLogger.error("NODE0314 Failed to set up TLS config. Exiting", e); + exit(1); + } + } + myname = "dmaap-dr-node"; + eventlogurl = getDrNodeProperties().getProperty("LogUploadURL", "https://feeds-drtr.web.att.com/internal/logs"); + intHttpPort = Integer.parseInt(getDrNodeProperties().getProperty("IntHttpPort", "80")); + intHttpsPort = Integer.parseInt(getDrNodeProperties().getProperty("IntHttpsPort", "443")); + extHttpsPort = Integer.parseInt(getDrNodeProperties().getProperty("ExtHttpsPort", "443")); + spooldir = getDrNodeProperties().getProperty("SpoolDir", "spool"); + File fdir = new File(spooldir + "/f"); fdir.mkdirs(); for (File junk : Objects.requireNonNull(fdir.listFiles())) { @@ -168,41 +162,21 @@ public class NodeConfigManager implements DeliveryQueueHelper { eelfLogger.error("NODE0313 Failed to clear junk files from " + fdir.getPath(), e); } } - logdir = drNodeProperties.getProperty("LogDir", "logs"); + logdir = getDrNodeProperties().getProperty("LogDir", "logs"); (new File(logdir)).mkdirs(); - logretention = Long.parseLong(drNodeProperties.getProperty("LogRetention", "30")) * 86400000L; + logretention = Long.parseLong(getDrNodeProperties().getProperty("LogRetention", "30")) * 86400000L; eventlogprefix = logdir + "/events"; eventlogsuffix = ".log"; - redirfile = drNodeProperties.getProperty("RedirectionFile", "etc/redirections.dat"); - kstype = drNodeProperties.getProperty("KeyStoreType", "PKCS12"); - ksfile = nodeAafPropsUtils.getPropAccess().getProperty("cadi_keystore"); - kspass = nodeAafPropsUtils.getDecryptedPass("cadi_keystore_password"); - kpass = nodeAafPropsUtils.getDecryptedPass("cadi_keystore_password"); - tstype = drNodeProperties.getProperty("TrustStoreType", "jks"); - tsfile = nodeAafPropsUtils.getPropAccess().getProperty("cadi_truststore"); - tspass = nodeAafPropsUtils.getDecryptedPass("cadi_truststore_password"); - if (tsfile != null && tsfile.length() > 0) { - System.setProperty("javax.net.ssl.trustStoreType", tstype); - System.setProperty("javax.net.ssl.trustStore", tsfile); - System.setProperty("javax.net.ssl.trustStorePassword", tspass); - } - nak = drNodeProperties.getProperty("NodeAuthKey", "Node123!"); - quiesce = new File(drNodeProperties.getProperty("QuiesceFile", "etc/SHUTDOWN")); - myname = NodeUtils.getCanonicalName(kstype, ksfile, kspass); - if (myname == null) { - NodeUtils.setIpAndFqdnForEelf(NODE_CONFIG_MANAGER); - eelfLogger.error(EelfMsgs.MESSAGE_KEYSTORE_FETCH_ERROR, ksfile); - eelfLogger.error("NODE0309 Unable to fetch canonical name from keystore file " + ksfile); - exit(1); - } - eelfLogger.debug("NODE0304 My certificate says my name is " + myname); - pid = new PublishId(myname); - long minrsinterval = Long.parseLong(drNodeProperties.getProperty("MinRedirSaveInterval", "10000")); - long minpfinterval = Long.parseLong(drNodeProperties.getProperty("MinProvFetchInterval", "10000")); - rdmgr = new RedirManager(redirfile, minrsinterval, timer); - pfetcher = new RateLimitedOperation(minpfinterval, timer) { + String redirfile = getDrNodeProperties().getProperty("RedirectionFile", "etc/redirections.dat"); + publishId = new PublishId(myname); + nak = getDrNodeProperties().getProperty("NodeAuthKey", "Node123!"); + quiesce = new File(getDrNodeProperties().getProperty("QuiesceFile", "etc/SHUTDOWN")); + rdmgr = new RedirManager(redirfile, + Long.parseLong(getDrNodeProperties().getProperty("MinRedirSaveInterval", "10000")), timer); + pfetcher = new RateLimitedOperation( + Long.parseLong(getDrNodeProperties().getProperty("MinProvFetchInterval", "10000")), timer) { public void run() { - fetchconfig(); + fetchNodeConfigFromProv(); } }; eelfLogger.debug("NODE0305 Attempting to fetch configuration at " + provurl); @@ -213,6 +187,9 @@ public class NodeConfigManager implements DeliveryQueueHelper { * Get the default node configuration manager. */ public static NodeConfigManager getInstance() { + if (base == null) { + base = new NodeConfigManager(); + } return base; } @@ -294,19 +271,19 @@ public class NodeConfigManager implements DeliveryQueueHelper { } } - private void fetchconfig() { + private void fetchNodeConfigFromProv() { try { - eelfLogger.debug("NodeConfigMan.fetchConfig: provurl:: " + provurl); + eelfLogger.debug("NodeConfigMan.fetchNodeConfigFromProv: provurl:: {}", provurl); URL url = new URL(provurl); Reader reader = new InputStreamReader(url.openStream()); - config = new NodeConfig(new ProvData(reader), myname, spooldir, port, nak); + nodeConfig = new NodeConfig(new ProvData(reader), myname, spooldir, extHttpsPort, nak); localconfig(); configtasks.startRun(); runTasks(); } catch (Exception e) { - NodeUtils.setIpAndFqdnForEelf("fetchconfigs"); + NodeUtils.setIpAndFqdnForEelf("fetchNodeConfigFromProv"); eelfLogger.error(EelfMsgs.MESSAGE_CONF_FAILED, e.toString()); - eelfLogger.error("NODE0306 Configuration failed " + e.toString() + " - try again later", e); + eelfLogger.error("NODE0306 Configuration failed {} - try again later", e); pfetcher.request(); } } @@ -339,8 +316,8 @@ public class NodeConfigManager implements DeliveryQueueHelper { /** * Am I configured. */ - boolean isConfigured() { - return config != null; + public boolean isConfigured() { + return nodeConfig != null; } /** @@ -357,7 +334,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return array of targets */ Target[] parseRouting(String routing) { - return config.parseRouting(routing); + return nodeConfig.parseRouting(routing); } /** @@ -368,7 +345,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return If the credentials and IP address are recognized, true, otherwise false. */ boolean isAnotherNode(String credentials, String ip) { - return config.isAnotherNode(credentials, ip); + return nodeConfig.isAnotherNode(credentials, ip); } /** @@ -380,18 +357,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return True if the IP and credentials are valid for the specified feed. */ String isPublishPermitted(String feedid, String credentials, String ip) { - return config.isPublishPermitted(feedid, credentials, ip); - } - - /** - * Check whether publication is allowed for AAF Feed. - * - * @param feedid The ID of the feed being requested - * @param ip The requesting IP address - * @return True if the IP and credentials are valid for the specified feed. - */ - String isPublishPermitted(String feedid, String ip) { - return config.isPublishPermitted(feedid, ip); + return nodeConfig.isPublishPermitted(feedid, credentials, ip); } /** @@ -401,7 +367,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return True if the delete file is permitted for the subscriber. */ boolean isDeletePermitted(String subId) { - return config.isDeletePermitted(subId); + return nodeConfig.isDeletePermitted(subId); } /** @@ -412,20 +378,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return Null if the credentials are invalid or the user if they are valid. */ String getAuthUser(String feedid, String credentials) { - return config.getAuthUser(feedid, credentials); - } - - /** - * AAF changes: TDP EPIC US# 307413 Check AAF_instance for feed ID in NodeConfig. - * - * @param feedid The ID of the feed specified - */ - String getAafInstance(String feedid) { - return config.getAafInstance(feedid); - } - - String getAafInstance() { - return aafInstance; + return nodeConfig.getAuthUser(feedid, credentials); } /** @@ -437,7 +390,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return Null if the request should be accepted or the correct hostname if it should be sent to another node. */ String getIngressNode(String feedid, String user, String ip) { - return config.getIngressNode(feedid, user, ip); + return nodeConfig.getIngressNode(feedid, user, ip); } /** @@ -447,7 +400,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return The value of the parameter or null if it is not defined. */ private String getProvParam(String name) { - return config.getProvParam(name); + return nodeConfig.getProvParam(name); } /** @@ -458,7 +411,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return The value of the parameter or deflt if it is not defined. */ private String getProvParam(String name, String defaultValue) { - name = config.getProvParam(name); + name = nodeConfig.getProvParam(name); if (name == null) { name = defaultValue; } @@ -469,20 +422,20 @@ public class NodeConfigManager implements DeliveryQueueHelper { * Generate a publish ID. */ public String getPublishId() { - return pid.next(); + return publishId.next(); } /** * Get all the outbound spooling destinations. This will include both subscriptions and nodes. */ - DestInfo[] getAllDests() { - return config.getAllDests(); + public DestInfo[] getAllDests() { + return nodeConfig.getAllDests(); } /** * Register a task to run whenever the configuration changes. */ - void registerConfigTask(Runnable task) { + public void registerConfigTask(Runnable task) { configtasks.addTask(task); } @@ -592,7 +545,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return The targets this feed should be delivered to */ Target[] getTargets(String feedid) { - return config.getTargets(feedid); + return nodeConfig.getTargets(feedid); } /** @@ -607,7 +560,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { */ String getSpoolDir(String subid, String remoteaddr) { if (provcheck.isFrom(remoteaddr)) { - String sdir = config.getSpoolDir(subid); + String sdir = nodeConfig.getSpoolDir(subid); if (sdir != null) { eelfLogger.debug("NODE0310 Received subscription reset request for subscription " + subid + " from provisioning server " + remoteaddr); @@ -625,111 +578,70 @@ public class NodeConfigManager implements DeliveryQueueHelper { /** * Get the base directory for spool directories. */ - String getSpoolBase() { + public String getSpoolBase() { return spooldir; } - /** - * Get the key store type. - */ - String getKSType() { - return kstype; - } - - /** - * Get the key store file. - */ - String getKSFile() { - return ksfile; - } - - /** - * Get the key store password. - */ - String getKSPass() { - return kspass; - } - - /** - * Get the key password. - */ - String getKPass() { - return kpass; - } - - - String getTstype() { - return tstype; - } - - String getTsfile() { - return tsfile; - } - - String getTspass() { - return tspass; - } - /** * Get the http port. */ int getHttpPort() { - return gfport; + return intHttpPort; } /** * Get the https port. */ int getHttpsPort() { - return svcport; + return intHttpsPort; } /** * Get the externally visible https port. */ int getExtHttpsPort() { - return port; + return extHttpsPort; } /** * Get the external name of this machine. */ - String getMyName() { + public String getMyName() { return myname; } /** * Get the number of threads to use for delivery. */ - int getDeliveryThreads() { + public int getDeliveryThreads() { return deliverythreads; } /** * Get the URL for uploading the event log data. */ - String getEventLogUrl() { + public String getEventLogUrl() { return eventlogurl; } /** * Get the prefix for the names of event log files. */ - String getEventLogPrefix() { + public String getEventLogPrefix() { return eventlogprefix; } /** * Get the suffix for the names of the event log files. */ - String getEventLogSuffix() { + public String getEventLogSuffix() { return eventlogsuffix; } /** * Get the interval between event log file rollovers. */ - String getEventLogInterval() { + public String getEventLogInterval() { return eventloginterval; } @@ -743,14 +655,14 @@ public class NodeConfigManager implements DeliveryQueueHelper { /** * Get the directory where the event and node log files live. */ - String getLogDir() { + public String getLogDir() { return logdir; } /** * How long do I keep log files (in milliseconds). */ - long getLogRetention() { + public long getLogRetention() { return logretention; } @@ -768,7 +680,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { * @return The feed ID */ public String getFeedId(String subid) { - return config.getFeedId(subid); + return nodeConfig.getFeedId(subid); } /** @@ -776,15 +688,15 @@ public class NodeConfigManager implements DeliveryQueueHelper { * * @return The Authorization string for this node */ - String getMyAuth() { - return config.getMyAuth(); + public String getMyAuth() { + return nodeConfig.getMyAuth(); } /** * Get the fraction of free spool disk space where we start throwing away undelivered files. This is * FREE_DISK_RED_PERCENT / 100.0. Default is 0.05. Limited by 0.01 <= FreeDiskStart <= 0.5. */ - double getFreeDiskStart() { + public double getFreeDiskStart() { return fdpstart; } @@ -792,50 +704,138 @@ public class NodeConfigManager implements DeliveryQueueHelper { * Get the fraction of free spool disk space where we stop throwing away undelivered files. This is * FREE_DISK_YELLOW_PERCENT / 100.0. Default is 0.2. Limited by FreeDiskStart <= FreeDiskStop <= 0.5. */ - double getFreeDiskStop() { + public double getFreeDiskStop() { return fdpstop; } - /** - * Disable and enable protocols. - */ - String[] getEnabledprotocols() { - return enabledprotocols; + protected boolean isTlsEnabled() { + return tlsEnabled; } - String getAafType() { - return aafType; + public static NodeTlsManager getNodeTlsManager() { + return nodeTlsManager; } - String getAafAction() { - return aafAction; - } + /** + * Generate publish IDs. + */ + static class PublishId { - boolean getCadiEnabled() { - return cadiEnabled; - } + private long nextuid; + private final String myname; + + /** + * Generate publish IDs for the specified name. + * + * @param myname Unique identifier for this publish ID generator (usually fqdn of server) + */ + public PublishId(String myname) { + this.myname = myname; + } - NodeAafPropsUtils getNodeAafPropsUtils() { - return nodeAafPropsUtils; + /** + * Generate a Data Router Publish ID that uniquely identifies the particular invocation of the Publish API for log + * correlation purposes. + */ + public synchronized String next() { + long now = System.currentTimeMillis(); + if (now < nextuid) { + now = nextuid; + } + nextuid = now + 1; + return (now + "." + myname); + } } /** - * Builds the permissions string to be verified. - * - * @param aafInstance The aaf instance - * @return The permissions + * Manage a list of tasks to be executed when an event occurs. This makes the following guarantees: + * */ - String getPermission(String aafInstance) { - try { - String type = getAafType(); - String action = getAafAction(); - if ("".equals(aafInstance)) { - aafInstance = getAafInstance(); + static class TaskList { + + private Iterator runlist; + private final HashSet tasks = new HashSet<>(); + private HashSet togo; + private HashSet sofar; + private HashSet added; + private HashSet removed; + + /** + * Start executing the sequence of tasks. + */ + synchronized void startRun() { + sofar = new HashSet<>(); + added = new HashSet<>(); + removed = new HashSet<>(); + togo = new HashSet<>(tasks); + runlist = togo.iterator(); + } + + /** + * Get the next task to execute. + */ + synchronized Runnable next() { + while (runlist != null) { + if (runlist.hasNext()) { + Runnable task = runlist.next(); + if (addTaskToSoFar(task)) { + return task; + } + } + if (!added.isEmpty()) { + togo = added; + added = new HashSet<>(); + removed.clear(); + runlist = togo.iterator(); + continue; + } + togo = null; + added = null; + removed = null; + sofar = null; + runlist = null; } - return type + "|" + aafInstance + "|" + action; - } catch (Exception e) { - eelfLogger.error("NODE0543 NodeConfigManager.getPermission: ", e); + return (null); + } + + /** + * Add a task to the list of tasks to run whenever the event occurs. + */ + synchronized void addTask(Runnable task) { + if (runlist != null) { + added.add(task); + removed.remove(task); + } + tasks.add(task); + } + + /** + * Remove a task from the list of tasks to run whenever the event occurs. + */ + synchronized void removeTask(Runnable task) { + if (runlist != null) { + removed.add(task); + added.remove(task); + } + tasks.remove(task); + } + + private boolean addTaskToSoFar(Runnable task) { + if (removed.contains(task)) { + return false; + } + if (sofar.contains(task)) { + return false; + } + sofar.add(task); + return true; } - return null; } }