Java tutorial
/******************************************************************************* * Copyright (c) 2007, 2014 Massimiliano Ziccardi * * 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 it.jnrpe.utils; import it.jnrpe.plugins.IPluginInterface; import it.jnrpe.plugins.IPluginRepository; import it.jnrpe.plugins.PluginConfigurationException; import it.jnrpe.plugins.PluginDefinition; import it.jnrpe.plugins.PluginOption; import it.jnrpe.plugins.annotations.Option; import it.jnrpe.plugins.annotations.Plugin; import it.jnrpe.plugins.annotations.PluginOptions; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.DOMReader; /** * An utility class that allows to define the plugin repository in an XML file * instead that using Java Code. * * @author Massimiliano Ziccardi * @version $Revision: 1.0 $ */ public final class PluginRepositoryUtil { /** * */ private PluginRepositoryUtil() { } /** * Loads a full repository definition from an XML file. * * @param repo * The repository that must be loaded * @param cl * The classloader to be used to instantiate the plugin classes * @param in * The stream to the XML file * @throws PluginConfigurationException * - */ public static void loadFromXmlPluginPackageDefinitions(final IPluginRepository repo, final ClassLoader cl, final InputStream in) throws PluginConfigurationException { for (PluginDefinition pd : loadFromXmlPluginPackageDefinitions(cl, in)) { repo.addPluginDefinition(pd); } } /** * Loads the plugins definitions from the jnrpe_plugins.xml file. * * @param cl * Classloader to be used to load classes * @param in * InputStream to the jnrpe_plugins.xml file * @return a collection of all the declared plugins * @throws PluginConfigurationException * on any error reading the plugin configuration */ @SuppressWarnings("unchecked") public static Collection<PluginDefinition> loadFromXmlPluginPackageDefinitions(final ClassLoader cl, final InputStream in) throws PluginConfigurationException { List<PluginDefinition> res = new ArrayList<PluginDefinition>(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document document; try { DocumentBuilder loader = factory.newDocumentBuilder(); DOMReader reader = new DOMReader(); document = reader.read(loader.parse(in)); } catch (Exception e) { throw new PluginConfigurationException(e.getMessage(), e); } Element plugins = document.getRootElement(); // TODO : validate against schema // iterate through child elements of root for (Iterator<Element> i = plugins.elementIterator(); i.hasNext();) { res.add(parsePluginDefinition(cl, i.next())); } return res; } /** * Loads the definition of a single plugin from an XML file. * * @param cl * The classloader to be used to instantiate the plugin class * @param in * The stream to the XML file * @return The plugin definition * @throws PluginConfigurationException * - */ public static PluginDefinition parseXmlPluginDefinition(final ClassLoader cl, final InputStream in) throws PluginConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document document; try { DocumentBuilder loader = factory.newDocumentBuilder(); DOMReader reader = new DOMReader(); document = reader.read(loader.parse(in)); } catch (Exception e) { throw new PluginConfigurationException(e.getMessage(), e); } Element plugin = document.getRootElement(); // TODO : validate against schema return parsePluginDefinition(cl, plugin); } /** * Returns the value of the given attribute name of element. If mandatory is * <code>true</code> and the attribute is blank or null, an exception is * thrown. * * @param element * The element whose attribute must be read * @param attributeName * The attribute name * @param mandatory * <code>true</code> if the attribute is mandatory * @return the attribute value * @throws PluginConfigurationException * if the attribute can't be found or is blank */ private static String getAttributeValue(final Element element, final String attributeName, final boolean mandatory) throws PluginConfigurationException { String returnValue = element.attributeValue(attributeName); if (mandatory) { if (StringUtils.isBlank(returnValue)) { throw new PluginConfigurationException( "Error loading plugin package : mandatory attribute " + attributeName + " not found"); } } return returnValue; } /** * Parse an XML plugin definition. * * @param cl * The classloader to be used to load classes * @param plugin * The plugin XML element * @return the parsed plugin definition * @throws PluginConfigurationException * - */ @SuppressWarnings("rawtypes") private static PluginDefinition parsePluginDefinition(final ClassLoader cl, final Element plugin) throws PluginConfigurationException { // Check if the plugin definition is inside its own file if (getAttributeValue(plugin, "definedIn", false) != null) { StreamManager sm = new StreamManager(); String sFileName = getAttributeValue(plugin, "definedIn", false); try { InputStream in = sm.handle(cl.getResourceAsStream(sFileName)); return parseXmlPluginDefinition(cl, in); } finally { sm.closeAll(); } } String pluginClass = getAttributeValue(plugin, "class", true); Class clazz; try { clazz = LoadedClassCache.getClass(cl, pluginClass); if (!IPluginInterface.class.isAssignableFrom(clazz)) { throw new PluginConfigurationException("Specified class '" + clazz.getName() + "' in the plugin.xml file does not implement " + "the IPluginInterface interface"); } if (isAnnotated(clazz)) { return loadFromPluginAnnotation(clazz); } } catch (ClassNotFoundException e) { throw new PluginConfigurationException(e.getMessage(), e); } // The class is not annotated not has an external definition file... // Loading from current xml file... String sDescription = getAttributeValue(plugin, "description", false); @SuppressWarnings("unchecked") PluginDefinition pluginDef = new PluginDefinition(getAttributeValue(plugin, "name", true), sDescription, clazz); parseCommandLine(pluginDef, plugin); return pluginDef; } /** * Updates the plugin definition with the commandline read from the xml * file. * * @param pluginDef * The plugin definition to be updated * @param xmlPluginElement * the xml element to be parsed */ @SuppressWarnings("rawtypes") private static void parseCommandLine(final PluginDefinition pluginDef, final Element xmlPluginElement) { Element commandLine = xmlPluginElement.element("command-line"); if (commandLine != null) { // The plugin has a command line... Element options = commandLine.element("options"); if (options == null) { // The command line is empty... return; } for (Iterator<Element> i = options.elementIterator(); i.hasNext();) { pluginDef.addOption(parsePluginOption(i.next())); } } } /** * Returns <code>true</code> if the class contains plugin annotations. * * @param clazz * The plugin class * @return <code>true</code> if the class contains plugin */ @SuppressWarnings({ "rawtypes", "unchecked" }) private static boolean isAnnotated(final Class clazz) { Plugin plugin = (Plugin) clazz.getAnnotation(Plugin.class); return plugin != null; } /** * Parse a plugin from class annotations. * * @param clazz * the plugin class * @return PluginDefinition */ @SuppressWarnings({ "rawtypes" }) public static PluginDefinition loadFromPluginAnnotation(final Class clazz) { return loadFromPluginAnnotation(clazz, null); } public static PluginDefinition loadFromPluginAnnotation(final IPluginInterface pluginInstance) { return loadFromPluginAnnotation(pluginInstance.getClass(), pluginInstance); } @SuppressWarnings({ "rawtypes", "unchecked" }) private static PluginDefinition loadFromPluginAnnotation(final Class clazz, final IPluginInterface pluginInstance) { Plugin plugin = (Plugin) clazz.getAnnotation(Plugin.class); PluginOptions options = (PluginOptions) clazz.getAnnotation(PluginOptions.class); String name = plugin.name(); String description = plugin.description(); PluginDefinition def; if (pluginInstance == null) { def = new PluginDefinition(name, description, clazz); } else { def = new PluginDefinition(name, description, pluginInstance); } for (Option option : options.value()) { def.addOption(parsePluginOption(option)); } return def; } /** * Parses a plugin option XML definition. * * @param option * The plugin option XML definition * @return The parsed plugin option */ private static PluginOption parsePluginOption(final Element option) { PluginOption po = new PluginOption(); po.setArgName(option.attributeValue("argName")); po.setArgsCount(Integer.valueOf(option.attributeValue("argsCount", "1"))); po.setArgsOptional(Boolean.valueOf(option.attributeValue("optionalArgs", "false"))); po.setDescription(option.attributeValue("description")); po.setHasArgs(Boolean.parseBoolean(option.attributeValue("hasArgs", "false"))); po.setLongOpt(option.attributeValue("longName")); po.setOption(option.attributeValue("shortName")); po.setRequired(Boolean.parseBoolean(option.attributeValue("required", "false"))); po.setType(option.attributeValue("type")); po.setValueSeparator(option.attributeValue("separator")); return po; } /** * Parses a plugin option from the annotation definition. * * @param option * the plugin option * @return PluginOption */ private static PluginOption parsePluginOption(final Option option) { PluginOption po = new PluginOption(); po.setArgName(option.argName()); po.setArgsOptional(option.optionalArgs()); po.setDescription(option.description()); po.setHasArgs(option.hasArgs()); po.setLongOpt(option.longName()); po.setOption(option.shortName()); po.setRequired(option.required()); return po; } }