/*
* 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) [2004, 2005, 2006], Hyperic, 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;
import org.hyperic.hq.product.pluginxml.PluginData;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.util.PluginLoader;
import org.hyperic.util.PluginLoaderException;
import org.hyperic.util.StringUtil;
import org.hyperic.util.config.ConfigSchema;
import org.hyperic.util.config.ConfigResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class GenericPlugin {
private static final String PROP_NETSTAT = "netservices.netstat";
/**
* Key used to store value of XML resource name attribute.
*/
public static final String PROP_NAME = "NAME";
static final String[] TYPE_LABELS = {
null, "platform.", "server.", "service."
};
PluginData data = null;
private static final boolean isWin32 =
PlatformDetector.IS_WIN32;
private String name = null;
private String version = null;
private TypeInfo type = null;
private PluginManager manager = null;
private ProductPlugin productPlugin = null;
protected ConfigResponse config;
private static String hostname = null;
public void setData(PluginData data) {
this.data = data;
}
public PluginData getPluginData() {
return this.data;
}
static String[] createTypeLabels(String prop) {
int len = TYPE_LABELS.length;
String[] labels = new String[len];
for (int i=0; i<len; i++) {
labels[i] = TYPE_LABELS[i] + prop;
}
return labels;
}
public static final String FILE_DELIM = ",";
public static final String FILE_DELIM_ESC = "%2C";
/**
* Expand a String to List of file names.
* @param value Comma delimited list of files
* @return List of String file names, which are trimmed and
* have unescaped any embedded commas ("%2C" -> ",")
*/
protected List toFileList(String value) {
List values = new ArrayList();
if (value == null) {
return values;
}
StringTokenizer tok =
new StringTokenizer(value, FILE_DELIM);
while (tok.hasMoreTokens()) {
String val = ((String)tok.nextToken()).trim();
values.add(StringUtil.replace(val,
FILE_DELIM_ESC,
FILE_DELIM));
}
return values;
}
/**
* Expand a String to array of absolute file names.
* @param value Expanded using toFileList()
* @param dir Parent directory used to resolve relative file names.
* @return Array of absolute file names.
*/
protected String[] getAbsoluteFiles(String value, String dir) {
if (dir == null) {
dir = File.separator;
}
List files = toFileList(value);
int size = files.size();
String[] absoluteFiles = new String[size];
for (int i=0; i<size; i++) {
File file = new File((String)files.get(i));
if (!file.isAbsolute()) {
file = new File(dir, file.toString());
}
absoluteFiles[i] = file.toString();
}
return absoluteFiles;
}
public boolean isNetStatEnabled() {
return !"false".equals(getManagerProperty(PROP_NETSTAT));
}
/**
* @return true if the current platform is in the Windows family.
*/
public static boolean isWin32() {
return isWin32;
}
static void setPlatformName(String name) {
hostname = name;
}
/**
* Method to assist with naming of resources.
*
* @return The hostname of the current platform.
*/
public static String getPlatformName(){
if (hostname == null) {
try {
hostname =
InetAddress.getLocalHost().getHostName();
} catch(Exception exc){
Sigar sigar = new Sigar();
try {
hostname =
sigar.getNetInfo().getHostName();
} catch (SigarException e) {
hostname = "localhost.unknown"; // Unlikely to occur
} finally {
sigar.close();
}
}
}
return hostname;
}
/**
* Unique name used by PluginManager.getPlugin
* @return Name of the plugin instance.
*/
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPluginVersion() {
return version;
}
public void setPluginVersion(String version) {
this.version = version;
}
/**
* @return The TypeInfo of this plugin from ProductPlugin.getTypes
*/
public TypeInfo getTypeInfo() {
return this.type;
}
public void setTypeInfo(TypeInfo type) {
this.type = type;
}
/**
* The ConfigSchema used to render config options for this resource
* in the UI and client shell.
* @param info The TypeInfo of this plugin from ProductPlugin.getTypes
* @param config ConfigReponse of the parent resource (if any).
* @return ConfigSchema for this resource.
*/
public ConfigSchema getConfigSchema(TypeInfo info, ConfigResponse config) {
return new ConfigSchema();
}
public ConfigSchema getCustomPropertiesSchema(String name) {
ConfigSchema schema = null;
if (this.data != null) {
schema = this.data.getCustomPropertiesSchema(name);
}
if (schema == null) {
schema = new ConfigSchema();
}
return schema;
}
public ConfigSchema getCustomPropertiesSchema(TypeInfo info) {
return getCustomPropertiesSchema(info.getName());
}
public ConfigSchema getCustomPropertiesSchema() {
return getCustomPropertiesSchema(getTypeInfo());
}
public String getManagerProperty(String key) {
return this.manager.getProperty(key);
}
/**
* Get a value defined by a <property> tag in the plugin's hq-plugin.xml
*/
public String getPluginProperty(String name) {
if (this.data == null) {
return null;
}
return this.data.getProperty(name);
}
/**
* Get all properties defined using <property> at the top-level
* in the plugin's hq-plugin.xml
*/
public Properties getProperties() {
return this.data.getProperties();
}
/**
* Get all properties defined using <property> within the resource
* tag (platform|server|service) for this type.
*/
public Properties getTypeProperties() {
//XXX ugly, should just store resource properties
//in another Map
Properties props = new Properties();
Map global = PluginData.getGlobalProperties();
String prefix = getTypeInfo().getName() + ".";
for (Iterator it=global.entrySet().iterator();
it.hasNext();)
{
Map.Entry entry = (Map.Entry)it.next();
String key = (String)entry.getKey();
if (!key.startsWith(prefix)) {
continue;
}
props.put(key.substring(prefix.length()),
entry.getValue());
}
return props;
}
/**
* Get a value defined by a <property> tag in the plugin's hq-plugin.xml,
* within a <server> or <service> tag for this plugin's type.
* <p>
* Same as:
* <code>
* getProperty(type + "." + name);
* </code>
*/
public String getTypeProperty(String type, String name) {
return getPluginProperty(type + "." + name);
}
/**
* If name property is not found for the given type,
* try using the type's parent. If not found using parent's
* type, try using top-level properties from hq-plugin.xml.
*/
public String getTypeProperty(TypeInfo type, String name) {
String value = getTypeProperty(type.getName(), name);
if (value != null) {
return value;
}
if (type.getType() == TypeInfo.TYPE_SERVICE) {
ServiceTypeInfo service = (ServiceTypeInfo)type;
return getTypeProperty(service.getServerName(), name);
}
return getPluginProperty(name);
}
/**
* Shortcut, same as:
* <code>
* getTypeProperty(getTypeInfo().getName(), name);
* </code>
*/
public String getTypeProperty(String name) {
return getTypeProperty(getTypeInfo().getName(), name);
}
/**
* Shortcut, same as:
* <code>
* getTypeProperty(type, PROP_NAME);
* </code>
*/
public String getTypeNameProperty(String type) {
return getTypeProperty(type, PROP_NAME);
}
/**
* Shortcut, same as:
* <code>
* getTypeNameProperty(getTypeInfo().getName());
* </code>
*/
public String getTypeNameProperty() {
return getTypeNameProperty(getTypeInfo().getName());
}
/**
* Called when the plugin is loaded on the server and on the agent side.
* @param manager The plugin manager for this plugin type.
*/
public void init(PluginManager manager)
throws PluginException {
this.manager = manager;
}
/**
* Called when the server or agent is shutdown.
* Use this method to cleanup any resources that were created
* during the init() method.
* @throws PluginException
*/
public void shutdown()
throws PluginException {
}
public ConfigResponse getConfig() {
return this.config;
}
/**
* Shortcut, same as getConfig().getValue(key)
*/
public String getConfig(String key) {
ConfigResponse config = getConfig();
if (config == null) {
return null;
}
return config.getValue(key);
}
public void configure(ConfigResponse config)
throws PluginException {
this.config = config;
}
public String getDefaultInstallPath() {
return
ProductPlugin.DEFAULT_INSTALLPATH +
File.separator +
getTypeInfo().getFormattedName();
}
/**
* @return ".bat" if isWin32() else ".sh"
*/
public static String getScriptExtension() {
return getScriptExtension(isWin32());
}
/**
* @return ".bat" if info.isWin32Platform() else ".sh"
*/
public String getScriptExtension(TypeInfo info) {
return getScriptExtension(info.isWin32Platform());
}
public static String getScriptExtension(boolean isWin32) {
return "." + (isWin32 ? "bat" : "sh");
}
/**
* Default name for getLog() method.
*/
protected String getLogName() {
//XXX '.' in versions effs things, logger things is a package delim
//return getTypeInfo().getName();
return this.getClass().getName();
}
/**
* Wrapper for LogFactory.getLog which uses the name
* returned by getLogName().
*/
protected Log getLog() {
return LogFactory.getLog(getLogName());
}
ProductPlugin getProductPlugin(String name) {
ProductPluginManager ppm =
(ProductPluginManager)this.manager.getParent();
PluginInfo info = this.manager.getPluginInfo(name);
if (info == null) {
//e.g. lookup for service name during autodiscovery
//no autodiscovery plugin registered for the service name
info =
ppm.getMeasurementPluginManager().getPluginInfo(name);
}
if (info == null) {
String msg = "Can't find PluginInfo for: " + name;
throw new IllegalArgumentException(msg);
}
return ppm.getProductPlugin(info.product);
}
/**
* Get the ProductPlugin that defined the TypeInfo for this
* plugin instance.
*/
public ProductPlugin getProductPlugin() {
if (this instanceof ProductPlugin) {
return (ProductPlugin)this;
}
if (this.productPlugin == null) {
this.productPlugin = getProductPlugin(getName());
}
//XXX seems this is the correct name to use and the above should be removed?
if ((this.productPlugin == null) && (getTypeInfo() != null)) {
this.productPlugin = getProductPlugin(getTypeInfo().getName());
}
return this.productPlugin;
}
/**
* Any jars that exist relative to the given installpath
* will be added to the plugin's classpath.
*/
protected void adjustClassPath(String installpath) {
ClassLoader cl = this.data.getClassLoader();
if (!(cl instanceof PluginLoader)) {
return;
}
PluginLoader loader = (PluginLoader)cl;
List classpath = this.data.getClassPath();
if (classpath == null) {
return;
}
boolean isDebug = getLog().isDebugEnabled();
URL[] orig = null;
if (isDebug) {
orig = loader.getURLs();
}
for (int i=0; i<classpath.size(); i++) {
String path = (String)classpath.get(i);
File file = new File(path);
if (file.isAbsolute() || file.exists()) {
continue;
}
file = new File(installpath, path);
if ((path.indexOf('*') != -1) || file.exists()) {
try {
loader.addURL(file.toString());
} catch (PluginLoaderException e) {
continue;
}
}
}
if (isDebug) {
URL[] curr = loader.getURLs();
if (curr.length > orig.length) {
for (int i=orig.length; i<curr.length; i++) {
getLog().debug("classpath += " +
curr[i].getFile());
}
}
else {
getLog().debug("classpath unchanged using: " +
installpath);
}
}
}
/**
* Wrapper around ClassLoader.getResource/getResourceAsStream
* to open a resource from this plugin's .jar file.
*/
public InputStream openResource(String name)
throws IOException {
ClassLoader loader = this.getClass().getClassLoader();
InputStream is = PluginData.openPluginResource(loader, name);
if (is == null) {
throw new FileNotFoundException("Cannot find: " + name);
}
return is;
}
public String getPluginClassName(String pluginType, String resourceType) {
return this.data.getPlugin(pluginType, resourceType);
}
}