You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2018/04/03 12:24:18 UTC

lucene-solr:jira/solr-12095: SOLR-12095: Validate trigger listeners too. Cleanup and test fixes.

Repository: lucene-solr
Updated Branches:
  refs/heads/jira/solr-12095 d83fcbd1f -> 3c0264f7b


SOLR-12095: Validate trigger listeners too. Cleanup and test fixes.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3c0264f7
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3c0264f7
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3c0264f7

Branch: refs/heads/jira/solr-12095
Commit: 3c0264f7b82d4f876423049eb18a066570da5d7a
Parents: d83fcbd
Author: Andrzej Bialecki <ab...@apache.org>
Authored: Tue Apr 3 14:23:49 2018 +0200
Committer: Andrzej Bialecki <ab...@apache.org>
Committed: Tue Apr 3 14:23:49 2018 +0200

----------------------------------------------------------------------
 .../cloud/autoscaling/AutoScalingHandler.java   |  20 +++-
 .../cloud/autoscaling/ComputePlanAction.java    |   5 +
 .../cloud/autoscaling/HttpTriggerListener.java  |  12 +-
 .../autoscaling/InactiveShardPlanAction.java    |  11 +-
 .../cloud/autoscaling/NodeAddedTrigger.java     |   3 -
 .../cloud/autoscaling/ScheduledTriggers.java    |   6 +-
 .../cloud/autoscaling/SearchRateTrigger.java    |   2 +-
 .../cloud/autoscaling/SystemLogListener.java    |  10 +-
 .../cloud/autoscaling/TriggerActionBase.java    |  15 ++-
 .../solr/cloud/autoscaling/TriggerBase.java     |  13 ++-
 .../solr/cloud/autoscaling/TriggerListener.java |  20 +++-
 .../cloud/autoscaling/TriggerListenerBase.java  |  52 ++++++++-
 .../autoscaling/TriggerValidationException.java |  14 ++-
 .../autoscaling/AutoScalingHandlerTest.java     | 117 +++++++++++++++++++
 .../autoscaling/HttpTriggerListenerTest.java    |  13 +--
 .../MetricTriggerIntegrationTest.java           |   5 +-
 .../cloud/autoscaling/NodeAddedTriggerTest.java |   5 +-
 .../cloud/autoscaling/NodeLostTriggerTest.java  |   6 +
 .../ScheduledMaintenanceTriggerTest.java        |   5 +-
 .../SearchRateTriggerIntegrationTest.java       |   5 +-
 .../TriggerCooldownIntegrationTest.java         |   5 +-
 .../autoscaling/TriggerIntegrationTest.java     |   5 +-
 .../cloud/autoscaling/sim/TestLargeCluster.java |   6 +-
 .../autoscaling/sim/TestTriggerIntegration.java |   4 +-
 24 files changed, 302 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
index f93a828..a69451e 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
@@ -458,14 +458,26 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
     }
     if (op.hasError()) return currentConfig;
 
+    AutoScalingConfig.TriggerListenerConfig listenerConfig = new AutoScalingConfig.TriggerListenerConfig(listenerName, op.getValuesExcluding("name"));
+
     // validate that we can load the listener class
     // todo allow creation from blobstore
+    TriggerListener listener = null;
     try {
-      loader.findClass(listenerClass, TriggerListener.class);
+      listener = loader.newInstance(listenerClass, TriggerListener.class);
+      listener.configure(loader, cloudManager, listenerConfig);
+    } catch (TriggerValidationException e) {
+      log.warn("invalid listener configuration", e);
+      op.addError("invalid listener configuration: " + e.toString());
+      return currentConfig;
     } catch (Exception e) {
       log.warn("error loading listener class ", e);
       op.addError("Listener not found: " + listenerClass + ". error message:" + e.getMessage());
       return currentConfig;
+    } finally {
+      if (listener != null) {
+        IOUtils.closeQuietly(listener);
+      }
     }
 
     Set<String> actionNames = new HashSet<>();
@@ -478,9 +490,8 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
       op.addError("The trigger '" + triggerName + "' does not have actions named: " + actionNames);
       return currentConfig;
     }
-    AutoScalingConfig.TriggerListenerConfig listener = new AutoScalingConfig.TriggerListenerConfig(listenerName, op.getValuesExcluding("name"));
     // todo - handle races between competing set-trigger and set-listener invocations
-    currentConfig = currentConfig.withTriggerListenerConfig(listener);
+    currentConfig = currentConfig.withTriggerListenerConfig(listenerConfig);
     return currentConfig;
   }
 
@@ -538,9 +549,6 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
     AutoScaling.Trigger t = null;
     try {
       t = triggerFactory.create(trigger.event, trigger.name, trigger.properties);
-    } catch (TriggerValidationException e) {
-      op.addError("Error validating trigger config " + trigger.name + ": " + e.getDetails());
-      return currentConfig;
     } catch (Exception e) {
       op.addError("Error validating trigger config " + trigger.name + ": " + e.toString());
       return currentConfig;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
index 55f432c..8f3175c 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
@@ -56,6 +56,11 @@ public class ComputePlanAction extends TriggerActionBase {
 
   Set<String> collections = new HashSet<>();
 
+  public ComputePlanAction() {
+    super();
+    TriggerUtils.validProperties(validProperties, "collections");
+  }
+
 
   @Override
   public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/HttpTriggerListener.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/HttpTriggerListener.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/HttpTriggerListener.java
index b35d0be..e620966 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/HttpTriggerListener.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/HttpTriggerListener.java
@@ -29,6 +29,7 @@ import org.apache.solr.client.solrj.cloud.SolrCloudManager;
 import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.PropertiesUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,9 +66,16 @@ public class HttpTriggerListener extends TriggerListenerBase {
   private int timeout = HttpClientUtil.DEFAULT_CONNECT_TIMEOUT;
   private boolean followRedirects;
 
+  public HttpTriggerListener() {
+    super();
+    TriggerUtils.requiredProperties(requiredProperties, validProperties, "url");
+    TriggerUtils.validProperties(validProperties, "payload", "contentType", "timeout", "followRedirects");
+    validPropertyPrefixes.add("header.");
+  }
+
   @Override
-  public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-    super.init(cloudManager, config);
+  public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+    super.configure(loader, cloudManager, config);
     urlTemplate = (String)config.properties.get("url");
     payloadTemplate = (String)config.properties.get("payload");
     contentType = (String)config.properties.get("contentType");

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
index 2cbe487..cb561f5 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
@@ -49,6 +49,11 @@ public class InactiveShardPlanAction extends TriggerActionBase {
 
   private int cleanupTTL;
 
+  public InactiveShardPlanAction() {
+    super();
+    TriggerUtils.validProperties(validProperties, TTL_PROP);
+  }
+
   @Override
   public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
     super.configure(loader, cloudManager, properties);
@@ -56,12 +61,10 @@ public class InactiveShardPlanAction extends TriggerActionBase {
     try {
       cleanupTTL = Integer.parseInt(cleanupStr);
     } catch (Exception e) {
-      log.warn("Invalid " + TTL_PROP + " value: '" + cleanupStr + "', using default " + DEFAULT_TTL_SECONDS);
-      cleanupTTL = DEFAULT_TTL_SECONDS;
+      throw new TriggerValidationException(getName(), TTL_PROP, "invalid value '" + cleanupStr + "': " + e.toString());
     }
     if (cleanupTTL < 0) {
-      log.warn("Invalid " + TTL_PROP + " value: '" + cleanupStr + "', using default " + DEFAULT_TTL_SECONDS);
-      cleanupTTL = DEFAULT_TTL_SECONDS;
+      throw new TriggerValidationException(getName(), TTL_PROP, "invalid value '" + cleanupStr + "', should be > 0. ");
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
index 484fbe0..ceea609 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
@@ -29,12 +29,9 @@ import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.solr.client.solrj.cloud.SolrCloudManager;
-
 import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventType;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.core.SolrResourceLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
index 9285292..c125209 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
@@ -685,7 +685,8 @@ public class ScheduledTriggers implements Closeable {
             }
             if (listener != null) {
               try {
-                listener.init(cloudManager, config);
+                listener.configure(loader, cloudManager, config);
+                listener.init();
                 listenersPerName.put(config.name, listener);
               } catch (Exception e) {
                 log.warn("Error initializing TriggerListener " + config, e);
@@ -769,6 +770,9 @@ public class ScheduledTriggers implements Closeable {
       updateLock.lock();
       try {
         for (TriggerListener listener : getTriggerListeners(trigger, stage)) {
+          if (!listener.isEnabled()) {
+            continue;
+          }
           if (actionName != null) {
             AutoScalingConfig.TriggerListenerConfig config = listener.getConfig();
             if (stage == TriggerEventProcessorStage.BEFORE_ACTION) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
index ffe7ba1..00bc6d8 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
@@ -85,7 +85,7 @@ public class SearchRateTrigger extends TriggerBase {
     try {
       rate = Double.parseDouble(rateString);
     } catch (Exception e) {
-      throw new TriggerValidationException("rate", "Invalid 'rate' configuration value: '" + rateString + "': " + e.toString());
+      throw new TriggerValidationException(name, "rate", "Invalid 'rate' configuration value: '" + rateString + "': " + e.toString());
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
index ea34112..c6f0e68 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SystemLogListener.java
@@ -41,6 +41,7 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.IdUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,21 +70,16 @@ public class SystemLogListener extends TriggerListenerBase {
   public static final String DOC_TYPE = "autoscaling_event";
 
   private String collection = CollectionAdminParams.SYSTEM_COLL;
-  private boolean enabled = true;
 
   @Override
-  public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-    super.init(cloudManager, config);
+  public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+    super.configure(loader, cloudManager, config);
     collection = (String)config.properties.getOrDefault(CollectionAdminParams.COLLECTION, CollectionAdminParams.SYSTEM_COLL);
-    enabled = Boolean.parseBoolean(String.valueOf(config.properties.getOrDefault("enabled", true)));
   }
 
   @Override
   public void onEvent(TriggerEvent event, TriggerEventProcessorStage stage, String actionName, ActionContext context,
                Throwable error, String message) throws Exception {
-    if (!enabled) {
-      return;
-    }
     try {
       SolrInputDocument doc = new SolrInputDocument();
       doc.addField(CommonParams.TYPE, DOC_TYPE);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
index ee2ce3c..7a9f34b 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
@@ -33,12 +33,21 @@ public abstract class TriggerActionBase implements TriggerAction {
   protected Map<String, Object> properties = new HashMap<>();
   protected SolrResourceLoader loader;
   protected SolrCloudManager cloudManager;
+  /**
+   * Set of valid property names. Subclasses may add to this set
+   * using {@link TriggerUtils#validProperties(Set, String...)}
+   */
   protected final Set<String> validProperties = new HashSet<>();
+  /**
+   * Set of required property names. Subclasses may add to this set
+   * using {@link TriggerUtils#requiredProperties(Set, Set, String...)}
+   * (required properties are also valid properties).
+   */
   protected final Set<String> requiredProperties = new HashSet<>();
 
   protected TriggerActionBase() {
-    TriggerUtils.validProperties(validProperties, "name");
-    TriggerUtils.requiredProperties(requiredProperties, validProperties, "class");
+    // not strictly needed here because they are already checked during instantiation
+    TriggerUtils.validProperties(validProperties, "name", "class");
   }
 
   @Override
@@ -67,7 +76,7 @@ public abstract class TriggerActionBase implements TriggerAction {
     Map<String, String> results = new HashMap<>();
     TriggerUtils.checkProperties(this.properties, results, requiredProperties, validProperties);
     if (!results.isEmpty()) {
-      throw new TriggerValidationException(results);
+      throw new TriggerValidationException(getName(), results);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
index c03557f..12d95bc 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
@@ -56,7 +56,16 @@ public abstract class TriggerBase implements AutoScaling.Trigger {
   protected SolrResourceLoader loader;
   protected DistribStateManager stateManager;
   protected final Map<String, Object> properties = new HashMap<>();
+  /**
+   * Set of valid property names. Subclasses may add to this set
+   * using {@link TriggerUtils#validProperties(Set, String...)}
+   */
   protected final Set<String> validProperties = new HashSet<>();
+  /**
+   * Set of required property names. Subclasses may add to this set
+   * using {@link TriggerUtils#requiredProperties(Set, Set, String...)}
+   * (required properties are also valid properties).
+   */
   protected final Set<String> requiredProperties = new HashSet<>();
   protected final TriggerEventType eventType;
   protected int waitForSecond;
@@ -72,7 +81,7 @@ public abstract class TriggerBase implements AutoScaling.Trigger {
     this.name = name;
 
     // subclasses may modify this set to include other supported properties
-    TriggerUtils.validProperties(validProperties, "name", "event", "enabled", "waitFor", "actions");
+    TriggerUtils.validProperties(validProperties, "name", "class", "event", "enabled", "waitFor", "actions");
   }
 
   @Override
@@ -106,7 +115,7 @@ public abstract class TriggerBase implements AutoScaling.Trigger {
     Map<String, String> results = new HashMap<>();
     TriggerUtils.checkProperties(this.properties, results, requiredProperties, validProperties);
     if (!results.isEmpty()) {
-      throw new TriggerValidationException(results);
+      throw new TriggerValidationException(name, results);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListener.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListener.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListener.java
index 663bf5a..234387f 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListener.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListener.java
@@ -21,6 +21,7 @@ import java.io.Closeable;
 import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
 import org.apache.solr.client.solrj.cloud.SolrCloudManager;
 import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
+import org.apache.solr.core.SolrResourceLoader;
 
 /**
  * Implementations of this interface are notified of stages in event processing that they were
@@ -28,7 +29,24 @@ import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage
  */
 public interface TriggerListener extends Closeable {
 
-  void init(SolrCloudManager dataProvider, AutoScalingConfig.TriggerListenerConfig config) throws Exception;
+  /**
+   * Called when listener is created but before it's initialized and used.
+   * This method should also verify that the configuration parameters are correct.
+   * It may be called multiple times.
+   * @param loader loader to use for instantiating sub-components
+   * @param cloudManager current instance of SolrCloudManager
+   * @param config coniguration
+   * @throws TriggerValidationException contains details of invalid configuration parameters.
+   */
+  void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException;
+
+  /**
+   * If this method returns false then the listener's {@link #onEvent(TriggerEvent, TriggerEventProcessorStage, String, ActionContext, Throwable, String)}
+   * method should not be called.
+   */
+  boolean isEnabled();
+
+  void init() throws Exception;
 
   AutoScalingConfig.TriggerListenerConfig getConfig();
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListenerBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListenerBase.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListenerBase.java
index 884ad97..7a323c7 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListenerBase.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerListenerBase.java
@@ -17,9 +17,14 @@
 package org.apache.solr.cloud.autoscaling;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
 import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.core.SolrResourceLoader;
 
 /**
  * Base class for implementations of {@link TriggerListener}.
@@ -28,11 +33,46 @@ public abstract class TriggerListenerBase implements TriggerListener {
 
   protected AutoScalingConfig.TriggerListenerConfig config;
   protected SolrCloudManager cloudManager;
+  protected SolrResourceLoader loader;
+  protected boolean enabled;
+  /**
+   * Set of valid property names. Subclasses may add to this set
+   * using {@link TriggerUtils#validProperties(Set, String...)}
+   */
+  protected final Set<String> validProperties = new HashSet<>();
+  /**
+   * Set of required property names. Subclasses may add to this set
+   * using {@link TriggerUtils#requiredProperties(Set, Set, String...)}
+   * (required properties are also valid properties).
+   */
+  protected final Set<String> requiredProperties = new HashSet<>();
+  /**
+   * Subclasses can add to this set if they want to allow arbitrary properties that
+   * start with one of valid prefixes.
+   */
+  protected final Set<String> validPropertyPrefixes = new HashSet<>();
+
+  protected TriggerListenerBase() {
+    TriggerUtils.requiredProperties(requiredProperties, validProperties, "trigger");
+    TriggerUtils.validProperties(validProperties, "name", "class", "stage", "beforeAction", "afterAction", "enabled");
+  }
 
   @Override
-  public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
+  public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+    this.loader = loader;
     this.cloudManager = cloudManager;
     this.config = config;
+    this.enabled = Boolean.parseBoolean(String.valueOf(config.properties.getOrDefault("enabled", true)));
+    // validate the config
+    Map<String, String> results = new HashMap<>();
+    // prepare a copy to treat the prefix-based properties
+    Map<String, Object> propsToCheck = new HashMap<>(config.properties);
+    propsToCheck.keySet().removeIf(k ->
+      validPropertyPrefixes.stream().anyMatch(p -> k.startsWith(p)));
+    TriggerUtils.checkProperties(propsToCheck, results, requiredProperties, validProperties);
+    if (!results.isEmpty()) {
+      throw new TriggerValidationException(config.name, results);
+    }
   }
 
   @Override
@@ -41,6 +81,16 @@ public abstract class TriggerListenerBase implements TriggerListener {
   }
 
   @Override
+  public boolean isEnabled() {
+    return enabled;
+  }
+
+  @Override
+  public void init() throws Exception {
+
+  }
+
+  @Override
   public void close() throws IOException {
 
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
index ac2542b..648e1e4 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
@@ -23,15 +23,18 @@ import java.util.Map;
  * This class represents errors found when validating trigger configuration.
  */
 public class TriggerValidationException extends Exception {
-  private Map<String, String> details = new HashMap<>();
+  private final Map<String, String> details = new HashMap<>();
+  private final String name;
 
   /**
    * Create an exception.
+   * @param name name of the trigger / action / listener that caused the exception
    * @param details details of invalid configuration - key is a property name,
    *                value is an error message.
    */
-  public TriggerValidationException(Map<String, String> details) {
+  public TriggerValidationException(String name, Map<String, String> details) {
     super();
+    this.name = name;
     if (details != null) {
       this.details.putAll(details);
     }
@@ -39,11 +42,13 @@ public class TriggerValidationException extends Exception {
 
   /**
    * Create an exception.
+   * @param name name of the trigger / action / listener that caused the exception
    * @param keyValues zero or even number of arguments representing symbolic key
    *                  (eg. property name) and the corresponding validation error message.
    */
-  public TriggerValidationException(String... keyValues) {
+  public TriggerValidationException(String name, String... keyValues) {
     super();
+    this.name = name;
     if (keyValues == null || keyValues.length == 0) {
       return;
     }
@@ -62,7 +67,8 @@ public class TriggerValidationException extends Exception {
   @Override
   public String toString() {
     return "TriggerValidationException{" +
-        "details=" + details +
+        "name=" + name +
+        ", details='" + details + '\'' +
         '}';
   }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
index 78b1274..b98ee70 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
@@ -439,6 +439,123 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     }
 
   }
+
+  @Test
+  public void testValidation() throws Exception {
+    CloudSolrClient solrClient = cluster.getSolrClient();
+
+    // unknown trigger properties
+    String setTriggerCommand = "{" +
+        "'set-trigger' : {" +
+        "'name' : 'node_lost_trigger'," +
+        "'event' : 'nodeLost'," +
+        "'waitFor' : '10m'," +
+        "'enabled' : true," +
+        "'foo': 'bar'," +
+        "'actions' : [" +
+        "{" +
+        "'name' : 'compute_plan'," +
+        "'class' : 'solr.ComputePlanAction'" +
+        "}]}}";
+    SolrRequest req = createAutoScalingRequest(SolrRequest.METHOD.POST, setTriggerCommand);
+
+    try {
+      solrClient.request(req);
+      fail("should have thrown Exception");
+    } catch (HttpSolrClient.RemoteSolrException e) {
+      // expected
+      assertTrue(String.valueOf(getObjectByPath(((HttpSolrClient.RemoteExecutionException) e).getMetaData(),
+          false, "error/details[0]/errorMessages[0]")).contains("foo=unknown property"));
+    }
+
+    // invalid trigger properties
+    setTriggerCommand = "{" +
+        "'set-trigger' : {" +
+        "'name' : 'search_rate_trigger'," +
+        "'event' : 'searchRate'," +
+        "'waitFor' : '10m'," +
+        "'enabled' : true," +
+        "'rate': 'foo'," +
+        "'actions' : [" +
+        "{" +
+        "'name' : 'compute_plan'," +
+        "'class' : 'solr.ComputePlanAction'" +
+        "}]}}";
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, setTriggerCommand);
+
+    try {
+      solrClient.request(req);
+      fail("should have thrown Exception");
+    } catch (HttpSolrClient.RemoteSolrException e) {
+      // expected
+      assertTrue(String.valueOf(getObjectByPath(((HttpSolrClient.RemoteExecutionException) e).getMetaData(),
+          false, "error/details[0]/errorMessages[0]")).contains("rate=Invalid 'rate' configuration value: 'foo'"));
+    }
+
+    // unknown trigger action properties
+    setTriggerCommand = "{" +
+        "'set-trigger' : {" +
+        "'name' : 'node_lost_trigger'," +
+        "'event' : 'nodeLost'," +
+        "'waitFor' : '10m'," +
+        "'enabled' : true," +
+        "'actions' : [" +
+        "{" +
+        "'name' : 'compute_plan'," +
+        "'foo' : 'bar'," +
+        "'class' : 'solr.ComputePlanAction'" +
+        "}]}}";
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, setTriggerCommand);
+
+    try {
+      solrClient.request(req);
+      fail("should have thrown Exception");
+    } catch (HttpSolrClient.RemoteSolrException e) {
+      // expected
+      assertTrue(String.valueOf(getObjectByPath(((HttpSolrClient.RemoteExecutionException) e).getMetaData(),
+          false, "error/details[0]/errorMessages[0]")).contains("foo=unknown property"));
+    }
+
+    // unknown trigger listener properties
+    setTriggerCommand = "{" +
+        "'set-trigger' : {" +
+        "'name' : 'node_lost_trigger'," +
+        "'event' : 'nodeLost'," +
+        "'waitFor' : '10m'," +
+        "'enabled' : true," +
+        "'actions' : [" +
+        "{" +
+        "'name' : 'compute_plan'," +
+        "'class' : 'solr.ComputePlanAction'" +
+        "}]}}";
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, setTriggerCommand);
+
+    NamedList<Object> response = solrClient.request(req);
+    assertEquals(response.get("result").toString(), "success");
+
+    String setListenerCommand = "{" +
+        "'set-listener' : " +
+        "{" +
+        "'name' : 'xyz'," +
+        "'trigger' : 'node_lost_trigger'," +
+        "'stage' : ['STARTED','ABORTED','SUCCEEDED']," +
+        "'foo' : 'bar'," +
+        "'beforeAction' : 'execute_plan'," +
+        "'class' : 'org.apache.solr.cloud.autoscaling.HttpTriggerListener'," +
+        "'url' : 'http://xyz.com/on_node_lost?node={$LOST_NODE_NAME}'" +
+        "}" +
+        "}";
+    req = createAutoScalingRequest(SolrRequest.METHOD.POST, setListenerCommand);
+    try {
+      solrClient.request(req);
+      fail("should have thrown Exception");
+    } catch (HttpSolrClient.RemoteSolrException e) {
+      // expected
+      assertTrue(String.valueOf(getObjectByPath(((HttpSolrClient.RemoteExecutionException) e).getMetaData(),
+          false, "error/details[0]/errorMessages[0]")).contains("foo=unknown property"));
+    }
+  }
+
   @Test
   public void testPolicyAndPreferences() throws Exception {
     CloudSolrClient solrClient = cluster.getSolrClient();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/HttpTriggerListenerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/HttpTriggerListenerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/HttpTriggerListenerTest.java
index 06fe9a0..eeb1a87 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/HttpTriggerListenerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/HttpTriggerListenerTest.java
@@ -102,10 +102,9 @@ public class HttpTriggerListenerTest extends SolrCloudTestCase {
         "'beforeAction' : 'test'," +
         "'afterAction' : ['test']," +
         "'class' : '" + HttpTriggerListener.class.getName() + "'," +
-        "'url' : '" + mockService.server.getURI().toString() + "/${config.name:invalid}/${config.properties.xyz:invalid}/${stage}'," +
+        "'url' : '" + mockService.server.getURI().toString() + "/${config.name:invalid}/${config.properties.beforeAction:invalid}/${stage}'," +
         "'payload': 'actionName=${actionName}, source=${event.source}, type=${event.eventType}'," +
-        "'header.X-Foo' : '${config.name:invalid}'," +
-        "'xyz': 'foo'" +
+        "'header.X-Foo' : '${config.name:invalid}'" +
         "}" +
         "}";
     req = createAutoScalingRequest(SolrRequest.METHOD.POST, setListenerCommand);
@@ -127,19 +126,19 @@ public class HttpTriggerListenerTest extends SolrCloudTestCase {
     requests.forEach(s -> assertTrue(s.contains("type=NODEADDED")));
 
     String request = requests.get(0);
-    assertTrue(request, request.startsWith("/foo/foo/STARTED"));
+    assertTrue(request, request.startsWith("/foo/test/STARTED"));
     assertTrue(request, request.contains("actionName=,")); // empty actionName
 
     request = requests.get(1);
-    assertTrue(request, request.startsWith("/foo/foo/BEFORE_ACTION"));
+    assertTrue(request, request.startsWith("/foo/test/BEFORE_ACTION"));
     assertTrue(request, request.contains("actionName=test,")); // actionName
 
     request = requests.get(2);
-    assertTrue(request, request.startsWith("/foo/foo/AFTER_ACTION"));
+    assertTrue(request, request.startsWith("/foo/test/AFTER_ACTION"));
     assertTrue(request, request.contains("actionName=test,")); // actionName
 
     request = requests.get(3);
-    assertTrue(request, request.startsWith("/foo/foo/SUCCEEDED"));
+    assertTrue(request, request.startsWith("/foo/test/SUCCEEDED"));
     assertTrue(request, request.contains("actionName=,")); // empty actionName
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerIntegrationTest.java
index 7b6da5a..67d943f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerIntegrationTest.java
@@ -40,6 +40,7 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.metrics.SolrCoreMetricManager;
 import org.apache.solr.util.LogLevel;
 import org.junit.BeforeClass;
@@ -227,8 +228,8 @@ public class MetricTriggerIntegrationTest extends SolrCloudTestCase {
 
   public static class TestTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
       listenerCreated.countDown();
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
index 0485d4a..a0b1ffb 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
@@ -46,7 +46,7 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
   private static AtomicBoolean actionCloseCalled = new AtomicBoolean(false);
 
   private AutoScaling.TriggerEventProcessor noFirstRunProcessor = event -> {
-    fail("Did not expect the listener to fire on first run!");
+    fail("Did not expect the processor to fire on first run! event=" + event);
     return true;
   };
 
@@ -76,6 +76,7 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
 
     try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
       trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      trigger.init();
       trigger.setProcessor(noFirstRunProcessor);
       trigger.run();
 
@@ -117,6 +118,7 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
     // and assert that the trigger doesn't fire at all
     try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
       trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      trigger.init();
       final long waitTime = 2;
       props.put("waitFor", waitTime);
       trigger.setProcessor(noFirstRunProcessor);
@@ -210,6 +212,7 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
     Map<String, Object> props = createTriggerProps(0);
     try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
       trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      trigger.init();
       trigger.setProcessor(noFirstRunProcessor);
       trigger.run(); // starts tracking live nodes
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
index 07988e1..00f7d42 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
@@ -77,6 +77,7 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
 
     try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger")) {
       trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      trigger.init();
       trigger.setProcessor(noFirstRunProcessor);
       trigger.run();
       String lostNodeName1 = cluster.getJettySolrRunner(1).getNodeName();
@@ -124,6 +125,7 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
       trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
       final long waitTime = 2;
       props.put("waitFor", waitTime);
+      trigger.init();
       trigger.setProcessor(noFirstRunProcessor);
       trigger.run();
 
@@ -227,6 +229,7 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
     Map<String, Object> props = createTriggerProps(0);
     try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger")) {
       trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      trigger.init();
       trigger.setProcessor(noFirstRunProcessor);
 
       JettySolrRunner newNode = cluster.startJettySolrRunner();
@@ -282,6 +285,7 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
 
     NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger");
     trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+    trigger.init();
     trigger.setProcessor(noFirstRunProcessor);
     trigger.run();
 
@@ -300,6 +304,7 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
 
     try (NodeLostTrigger newTrigger = new NodeLostTrigger("some_different_name"))  {
       newTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      newTrigger.init();
       try {
         newTrigger.restoreState(trigger);
         fail("Trigger should only be able to restore state from an old trigger of the same name");
@@ -310,6 +315,7 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
 
     try (NodeLostTrigger newTrigger = new NodeLostTrigger("node_lost_trigger")) {
       newTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
+      newTrigger.init();
       AtomicBoolean fired = new AtomicBoolean(false);
       AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
       newTrigger.setProcessor(event -> {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
index acd548c..ffcab4d 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledMaintenanceTriggerTest.java
@@ -37,6 +37,7 @@ import org.apache.solr.cloud.autoscaling.sim.SimCloudManager;
 import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.LogLevel;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -122,8 +123,8 @@ public class ScheduledMaintenanceTriggerTest extends SolrCloudTestCase {
 
   public static class CapturingTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
       listenerCreated.countDown();
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerIntegrationTest.java
index 547be5c..796670a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerIntegrationTest.java
@@ -41,6 +41,7 @@ import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.LogLevel;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -202,8 +203,8 @@ public class SearchRateTriggerIntegrationTest extends SolrCloudTestCase {
 
   public static class TestTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
       listenerCreated.countDown();
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerCooldownIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerCooldownIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerCooldownIntegrationTest.java
index e6e4116..6cf424a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerCooldownIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerCooldownIntegrationTest.java
@@ -38,6 +38,7 @@ import org.apache.solr.client.solrj.impl.CloudSolrClient;
 import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.params.AutoScalingParams;
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.LogLevel;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -223,8 +224,8 @@ public class TriggerCooldownIntegrationTest extends SolrCloudTestCase {
 
   public static class TestTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
       listenerCreated.countDown();
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
index cdfa55b..454a935 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
@@ -46,6 +46,7 @@ import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.TimeSource;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.LogLevel;
 import org.apache.zookeeper.data.Stat;
 import org.junit.Before;
@@ -504,8 +505,8 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
 
   public static class TestTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
       listenerCreated.countDown();
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestLargeCluster.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestLargeCluster.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestLargeCluster.java
index 4cd74e6..14ac40f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestLargeCluster.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestLargeCluster.java
@@ -50,12 +50,14 @@ import org.apache.solr.cloud.autoscaling.TriggerActionBase;
 import org.apache.solr.cloud.autoscaling.TriggerEvent;
 import org.apache.solr.cloud.autoscaling.TriggerListenerBase;
 import org.apache.solr.cloud.autoscaling.CapturedEvent;
+import org.apache.solr.cloud.autoscaling.TriggerValidationException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.params.CollectionParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.util.LogLevel;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -108,8 +110,8 @@ public class TestLargeCluster extends SimSolrCloudTestCase {
 
   public static class TestTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c0264f7/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
index 9586a2f..31e3636 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
@@ -887,8 +887,8 @@ public class TestTriggerIntegration extends SimSolrCloudTestCase {
 
   public static class TestTriggerListener extends TriggerListenerBase {
     @Override
-    public void init(SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) {
-      super.init(cloudManager, config);
+    public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, AutoScalingConfig.TriggerListenerConfig config) throws TriggerValidationException {
+      super.configure(loader, cloudManager, config);
       listenerCreated.countDown();
     }