diff --git a/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java b/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java
index a0eae64..7eb1f43 100644
--- a/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java
+++ b/azkaban-web-server/src/main/java/azkaban/webapp/AzkabanWebServer.java
@@ -75,7 +75,6 @@ import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
@@ -344,10 +343,8 @@ public class AzkabanWebServer extends AzkabanServer {
loadViewerPlugins(root, viewerPluginDir, app.getVelocityEngine());
// triggerplugin
- final String triggerPluginDir =
- azkabanSettings.getString("trigger.plugin.dir", "plugins/triggers");
final Map<String, TriggerPlugin> triggerPlugins =
- loadTriggerPlugins(root, triggerPluginDir, app);
+ new TriggerPluginLoader(azkabanSettings).loadTriggerPlugins(root);
app.setTriggerPlugins(triggerPlugins);
// always have basic time trigger
// TODO: find something else to do the job
@@ -356,149 +353,6 @@ public class AzkabanWebServer extends AzkabanServer {
root.setAttribute(Constants.AZKABAN_SERVLET_CONTEXT_KEY, app);
}
- private static Map<String, TriggerPlugin> loadTriggerPlugins(final Context root,
- final String pluginPath, final AzkabanWebServer azkabanWebApp) {
- final File triggerPluginPath = new File(pluginPath);
- if (!triggerPluginPath.exists()) {
- return new HashMap<>();
- }
-
- final Map<String, TriggerPlugin> installedTriggerPlugins =
- new HashMap<>();
- final ClassLoader parentLoader = AzkabanWebServer.class.getClassLoader();
- final File[] pluginDirs = triggerPluginPath.listFiles();
- final ArrayList<String> jarPaths = new ArrayList<>();
- for (final File pluginDir : pluginDirs) {
- if (!pluginDir.exists()) {
- logger.error("Error! Trigger plugin path " + pluginDir.getPath()
- + " doesn't exist.");
- continue;
- }
-
- if (!pluginDir.isDirectory()) {
- logger.error("The plugin path " + pluginDir + " is not a directory.");
- continue;
- }
-
- // Load the conf directory
- final File propertiesDir = new File(pluginDir, "conf");
- Props pluginProps = null;
- if (propertiesDir.exists() && propertiesDir.isDirectory()) {
- final File propertiesFile = new File(propertiesDir, "plugin.properties");
- final File propertiesOverrideFile =
- new File(propertiesDir, "override.properties");
-
- if (propertiesFile.exists()) {
- if (propertiesOverrideFile.exists()) {
- pluginProps =
- PropsUtils.loadProps(null, propertiesFile,
- propertiesOverrideFile);
- } else {
- pluginProps = PropsUtils.loadProps(null, propertiesFile);
- }
- } else {
- logger.error("Plugin conf file " + propertiesFile + " not found.");
- continue;
- }
- } else {
- logger.error("Plugin conf path " + propertiesDir + " not found.");
- continue;
- }
-
- final String pluginName = pluginProps.getString("trigger.name");
- final List<String> extLibClasspath =
- pluginProps.getStringList("trigger.external.classpaths",
- (List<String>) null);
-
- final String pluginClass = pluginProps.getString("trigger.class");
- if (pluginClass == null) {
- logger.error("Trigger class is not set.");
- } else {
- logger.error("Plugin class " + pluginClass);
- }
-
- URLClassLoader urlClassLoader = null;
- final File libDir = new File(pluginDir, "lib");
- if (libDir.exists() && libDir.isDirectory()) {
- final File[] files = libDir.listFiles();
-
- final ArrayList<URL> urls = new ArrayList<>();
- for (int i = 0; i < files.length; ++i) {
- try {
- final URL url = files[i].toURI().toURL();
- urls.add(url);
- } catch (final MalformedURLException e) {
- logger.error(e);
- }
- }
- if (extLibClasspath != null) {
- for (final String extLib : extLibClasspath) {
- try {
- final File file = new File(pluginDir, extLib);
- final URL url = file.toURI().toURL();
- urls.add(url);
- } catch (final MalformedURLException e) {
- logger.error(e);
- }
- }
- }
-
- urlClassLoader =
- new URLClassLoader(urls.toArray(new URL[urls.size()]), parentLoader);
- } else {
- logger.error("Library path " + propertiesDir + " not found.");
- continue;
- }
-
- Class<?> triggerClass = null;
- try {
- triggerClass = urlClassLoader.loadClass(pluginClass);
- } catch (final ClassNotFoundException e) {
- logger.error("Class " + pluginClass + " not found.");
- continue;
- }
-
- final String source = FileIOUtils.getSourcePathFromClass(triggerClass);
- logger.info("Source jar " + source);
- jarPaths.add("jar:file:" + source);
-
- Constructor<?> constructor = null;
- try {
- constructor =
- triggerClass.getConstructor(String.class, Props.class,
- Context.class, AzkabanWebServer.class);
- } catch (final NoSuchMethodException e) {
- logger.error("Constructor not found in " + pluginClass);
- continue;
- }
-
- Object obj = null;
- try {
- obj =
- constructor.newInstance(pluginName, pluginProps, root,
- azkabanWebApp);
- } catch (final Exception e) {
- logger.error(e);
- }
-
- if (!(obj instanceof TriggerPlugin)) {
- logger.error("The object is not an TriggerPlugin");
- continue;
- }
-
- final TriggerPlugin plugin = (TriggerPlugin) obj;
- installedTriggerPlugins.put(pluginName, plugin);
- }
-
- // Velocity needs the jar resource paths to be set.
- final String jarResourcePath = StringUtils.join(jarPaths, ", ");
- logger.info("Setting jar resource path " + jarResourcePath);
- final VelocityEngine ve = azkabanWebApp.getVelocityEngine();
- ve.addProperty("jar.resource.loader.path", jarResourcePath);
-
- return installedTriggerPlugins;
- }
-
private static void loadViewerPlugins(final Context root, final String pluginPath,
final VelocityEngine ve) {
final File viewerPluginPath = new File(pluginPath);
diff --git a/azkaban-web-server/src/main/java/azkaban/webapp/TriggerPluginLoader.java b/azkaban-web-server/src/main/java/azkaban/webapp/TriggerPluginLoader.java
new file mode 100644
index 0000000..a1aea54
--- /dev/null
+++ b/azkaban-web-server/src/main/java/azkaban/webapp/TriggerPluginLoader.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2017 LinkedIn Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ */
+
+package azkaban.webapp;
+
+import static azkaban.ServiceProvider.SERVICE_PROVIDER;
+
+import azkaban.utils.FileIOUtils;
+import azkaban.utils.Props;
+import azkaban.utils.PropsUtils;
+import azkaban.webapp.plugin.TriggerPlugin;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.velocity.app.VelocityEngine;
+import org.mortbay.jetty.servlet.Context;
+
+public class TriggerPluginLoader {
+
+ private static final Logger log = Logger.getLogger(TriggerPluginLoader.class);
+ private final String pluginPath;
+
+ public TriggerPluginLoader(final Props props) {
+ this.pluginPath = props.getString("trigger.plugin.dir", "plugins/triggers");
+ }
+
+ public Map<String, TriggerPlugin> loadTriggerPlugins(final Context root) {
+ /*
+ * TODO spyne: TriggerPluginLoader should not have any dependency on Azkaban Web Server
+ **/
+ final AzkabanWebServer azkabanWebServer = SERVICE_PROVIDER.getInstance(AzkabanWebServer.class);
+ final File triggerPluginPath = new File(this.pluginPath);
+ if (!triggerPluginPath.exists()) {
+ return new HashMap<>();
+ }
+
+ final Map<String, TriggerPlugin> installedTriggerPlugins =
+ new HashMap<>();
+ final ClassLoader parentLoader = AzkabanWebServer.class.getClassLoader();
+ final File[] pluginDirs = triggerPluginPath.listFiles();
+ final ArrayList<String> jarPaths = new ArrayList<>();
+ for (final File pluginDir : pluginDirs) {
+ if (!pluginDir.exists()) {
+ log.error("Error! Trigger plugin path " + pluginDir.getPath()
+ + " doesn't exist.");
+ continue;
+ }
+
+ if (!pluginDir.isDirectory()) {
+ log.error("The plugin path " + pluginDir + " is not a directory.");
+ continue;
+ }
+
+ // Load the conf directory
+ final File propertiesDir = new File(pluginDir, "conf");
+ Props pluginProps = null;
+ if (propertiesDir.exists() && propertiesDir.isDirectory()) {
+ final File propertiesFile = new File(propertiesDir, "plugin.properties");
+ final File propertiesOverrideFile =
+ new File(propertiesDir, "override.properties");
+
+ if (propertiesFile.exists()) {
+ if (propertiesOverrideFile.exists()) {
+ pluginProps =
+ PropsUtils.loadProps(null, propertiesFile,
+ propertiesOverrideFile);
+ } else {
+ pluginProps = PropsUtils.loadProps(null, propertiesFile);
+ }
+ } else {
+ log.error("Plugin conf file " + propertiesFile + " not found.");
+ continue;
+ }
+ } else {
+ log.error("Plugin conf path " + propertiesDir + " not found.");
+ continue;
+ }
+
+ final String pluginName = pluginProps.getString("trigger.name");
+ final List<String> extLibClasspath =
+ pluginProps.getStringList("trigger.external.classpaths",
+ (List<String>) null);
+
+ final String pluginClass = pluginProps.getString("trigger.class");
+ if (pluginClass == null) {
+ log.error("Trigger class is not set.");
+ } else {
+ log.error("Plugin class " + pluginClass);
+ }
+
+ URLClassLoader urlClassLoader = null;
+ final File libDir = new File(pluginDir, "lib");
+ if (libDir.exists() && libDir.isDirectory()) {
+ final File[] files = libDir.listFiles();
+
+ final ArrayList<URL> urls = new ArrayList<>();
+ for (int i = 0; i < files.length; ++i) {
+ try {
+ final URL url = files[i].toURI().toURL();
+ urls.add(url);
+ } catch (final MalformedURLException e) {
+ log.error(e);
+ }
+ }
+ if (extLibClasspath != null) {
+ for (final String extLib : extLibClasspath) {
+ try {
+ final File file = new File(pluginDir, extLib);
+ final URL url = file.toURI().toURL();
+ urls.add(url);
+ } catch (final MalformedURLException e) {
+ log.error(e);
+ }
+ }
+ }
+
+ urlClassLoader =
+ new URLClassLoader(urls.toArray(new URL[urls.size()]), parentLoader);
+ } else {
+ log.error("Library path " + propertiesDir + " not found.");
+ continue;
+ }
+
+ Class<?> triggerClass = null;
+ try {
+ triggerClass = urlClassLoader.loadClass(pluginClass);
+ } catch (final ClassNotFoundException e) {
+ log.error("Class " + pluginClass + " not found.");
+ continue;
+ }
+
+ final String source = FileIOUtils.getSourcePathFromClass(triggerClass);
+ log.info("Source jar " + source);
+ jarPaths.add("jar:file:" + source);
+
+ Constructor<?> constructor = null;
+ try {
+ constructor =
+ triggerClass.getConstructor(String.class, Props.class,
+ Context.class, AzkabanWebServer.class);
+ } catch (final NoSuchMethodException e) {
+ log.error("Constructor not found in " + pluginClass);
+ continue;
+ }
+
+ Object obj = null;
+ try {
+ obj =
+ constructor.newInstance(pluginName, pluginProps, root,
+ azkabanWebServer);
+ } catch (final Exception e) {
+ log.error(e);
+ }
+
+ if (!(obj instanceof TriggerPlugin)) {
+ log.error("The object is not an TriggerPlugin");
+ continue;
+ }
+
+ final TriggerPlugin plugin = (TriggerPlugin) obj;
+ installedTriggerPlugins.put(pluginName, plugin);
+ }
+
+ // Velocity needs the jar resource paths to be set.
+ final String jarResourcePath = StringUtils.join(jarPaths, ", ");
+ log.info("Setting jar resource path " + jarResourcePath);
+ final VelocityEngine ve = azkabanWebServer.getVelocityEngine();
+ ve.addProperty("jar.resource.loader.path", jarResourcePath);
+
+ return installedTriggerPlugins;
+ }
+
+}