Java tutorial
/* * 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; } }