/** * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2010], VMware, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * */ package org.hyperic.hq.product.validation; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.hyperic.hq.product.pluginxml.PluginData; import org.hyperic.hq.product.pluginxml.PluginParser; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; /** * Validates plugin XML files. Executed as part of each plugin's build cycle * (during process-resources phase) * @author jhickey * */ public class PluginXmlValidator { private static final String[] SHARED_XML_LOCATIONS = { "process-plugin/src/main/resources", "jvm-plugin/src/main/resources", "hibernate-plugin/src/main/resources" }; private String pluginDir; /** * * @param pluginDir The top level directory containing all the plugins under * src control. Should be /path to local hq repo/hq-plugin */ public PluginXmlValidator(String pluginDir) { this.pluginDir = pluginDir; } private class BuildTimeEntityResolver implements EntityResolver { private PluginData data; BuildTimeEntityResolver(PluginData data) { this.data = data; } private String resolveParentFile(String name) { if (this.data.getFile() != null) { // look for the file using the plugin's location File dir = new File(this.data.getFile()).getParentFile(); while (dir != null) { File resolved = new File(dir, name); if (resolved.exists()) { return resolved.toString(); } dir = dir.getParentFile(); } } return name; } private boolean isPluginFile(String name) { return name.startsWith(PluginData.PLUGINS_PREFIX); } private String resolvePluginFile(String name) throws FileNotFoundException { // Resolve any included XML paths beginning with pdk/plugins. Strip // off "pdk/plugins" in favor of location of shared XML under src // control for (String sharedLocation : SHARED_XML_LOCATIONS) { File referencedFile = new File(pluginDir + "/" + sharedLocation + "/" + name.substring(PluginData.PLUGINS_PREFIX.length())); if (referencedFile.exists()) { return referencedFile.getAbsolutePath(); } } throw new FileNotFoundException("Unable to find included XML file: " + name.substring(PluginData.PLUGINS_PREFIX.length()) + " under any shared locations in plugin dir: " + pluginDir); } // resolve external references to a set of shared metadata private String resolveFile(String name) throws FileNotFoundException { if (isPluginFile(name)) { return resolvePluginFile(name); } else { return resolveParentFile(name); } } @SuppressWarnings("unchecked") public InputSource resolveEntity(String publicId, String systemId) { try { String name = null; // WTF. certain xerces impls will pass the relative uri as-is // others prepend the file:// protocol. if (systemId.startsWith("/")) { name = systemId; } else if (systemId.startsWith("file:/")) { name = new URL(systemId).getFile(); } if (name != null) { String resolvedName; if (name.startsWith("/")) { name = name.substring(1); } resolvedName = resolveFile(name); InputStream is = new FileInputStream(resolvedName); this.data.getIncludes().add(resolvedName); return new InputSource(is); } } catch (Exception e) { e.printStackTrace(); } return null; } } public void validatePluginXML(String name) throws Exception { File descriptor = new File(name); if (!descriptor.exists()) { System.out.println("Skipping " + name + " validation " + "(does not exist)"); return; } PluginParser parser = new PluginParser(); PluginData data = new PluginData(); FileInputStream is = null; data.setFile(name); try { System.out.println("Validating " + name); is = new FileInputStream(descriptor); parser.parse(is, data, new BuildTimeEntityResolver(data)); } finally { if (is != null) { try { is.close(); } catch (IOException e) { } } } } public static void main(String[] args) { if (args.length != 1) { System.err.println("Usage: PluginXmlValidator <plugin dir>"); System.exit(1); } Logger rootLogger = Logger.getRootLogger(); rootLogger.setLevel(Level.INFO); PatternLayout layout = new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN); rootLogger.addAppender(new ConsoleAppender(layout)); final String pluginDir = args[0]; // First try src/main/resources/etc/hq-plugin.xml. Java plugins should // have this. final String desc = "/src/main/resources/" + PluginData.PLUGIN_XML; String plugin = pluginDir + desc; if (!new File(plugin).exists()) { // Maybe it is an XML Plugin - try // src/main/resources/<pluginName>.xml final String pluginDirName = new File(pluginDir).getName(); plugin = pluginDir + "/src/main/resources/" + pluginDirName + ".xml"; if (!new File(plugin).exists()) { System.err.println("Unable to find plugin XML to validate"); System.exit(1); } } PluginXmlValidator validator = new PluginXmlValidator(new File(pluginDir).getParent()); try { validator.validatePluginXML(plugin); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } }