/* * 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.executor; import azkaban.alert.Alerter; import azkaban.utils.Emailer; import azkaban.utils.FileIOUtils; import azkaban.utils.Props; import azkaban.utils.PropsUtils; import com.google.inject.Inject; 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.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; public class AlerterHolder { private Map<String, Alerter> alerters; private static Logger logger = Logger.getLogger(AlerterHolder.class); @Inject public AlerterHolder(Props props) { try { alerters = loadAlerters(props); } catch (Exception ex) { logger.error(ex); alerters = new HashMap<>(); } } private Map<String, Alerter> loadAlerters(Props props) { Map<String, Alerter> allAlerters = new HashMap<String, Alerter>(); // load built-in alerters Emailer mailAlerter = new Emailer(props); allAlerters.put("email", mailAlerter); // load all plugin alerters String pluginDir = props.getString("alerter.plugin.dir", "plugins/alerter"); allAlerters.putAll(loadPluginAlerters(pluginDir)); return allAlerters; } private Map<String, Alerter> loadPluginAlerters(String pluginPath) { File alerterPluginPath = new File(pluginPath); if (!alerterPluginPath.exists()) { return Collections.<String, Alerter> emptyMap(); } Map<String, Alerter> installedAlerterPlugins = new HashMap<String, Alerter>(); ClassLoader parentLoader = getClass().getClassLoader(); File[] pluginDirs = alerterPluginPath.listFiles(); ArrayList<String> jarPaths = new ArrayList<String>(); for (File pluginDir : pluginDirs) { if (!pluginDir.isDirectory()) { logger.error("The plugin path " + pluginDir + " is not a directory."); continue; } // Load the conf directory File propertiesDir = new File(pluginDir, "conf"); Props pluginProps = null; if (propertiesDir.exists() && propertiesDir.isDirectory()) { File propertiesFile = new File(propertiesDir, "plugin.properties"); 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; } String pluginName = pluginProps.getString("alerter.name"); List<String> extLibClasspath = pluginProps.getStringList("alerter.external.classpaths", (List<String>) null); String pluginClass = pluginProps.getString("alerter.class"); if (pluginClass == null) { logger.error("Alerter class is not set."); } else { logger.info("Plugin class " + pluginClass); } URLClassLoader urlClassLoader = null; File libDir = new File(pluginDir, "lib"); if (libDir.exists() && libDir.isDirectory()) { File[] files = libDir.listFiles(); ArrayList<URL> urls = new ArrayList<URL>(); for (int i = 0; i < files.length; ++i) { try { URL url = files[i].toURI().toURL(); urls.add(url); } catch (MalformedURLException e) { logger.error(e); } } if (extLibClasspath != null) { for (String extLib : extLibClasspath) { try { File file = new File(pluginDir, extLib); URL url = file.toURI().toURL(); urls.add(url); } catch (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<?> alerterClass = null; try { alerterClass = urlClassLoader.loadClass(pluginClass); } catch (ClassNotFoundException e) { logger.error("Class " + pluginClass + " not found."); continue; } String source = FileIOUtils.getSourcePathFromClass(alerterClass); logger.info("Source jar " + source); jarPaths.add("jar:file:" + source); Constructor<?> constructor = null; try { constructor = alerterClass.getConstructor(Props.class); } catch (NoSuchMethodException e) { logger.error("Constructor not found in " + pluginClass); continue; } Object obj = null; try { obj = constructor.newInstance(pluginProps); } catch (Exception e) { logger.error(e); } if (!(obj instanceof Alerter)) { logger.error("The object is not an Alerter"); continue; } Alerter plugin = (Alerter) obj; installedAlerterPlugins.put(pluginName, plugin); } return installedAlerterPlugins; } public Alerter get(String alerterType) { return this.alerters.get(alerterType); } }