/*
* 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.plugin.websphere;
import com.ibm.websphere.management.AdminClient;
import com.ibm.websphere.management.AdminClientFactory;
import com.ibm.websphere.management.exception.ConnectorException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.product.Metric;
import org.hyperic.hq.product.MetricInvalidException;
import org.hyperic.hq.product.MetricNotFoundException;
import org.hyperic.hq.product.MetricUnreachableException;
import org.hyperic.hq.product.PluginException;
/**
* WebSphere JMX Utils for version 5.0 + These utils simply wrap
* javax.management.* and WebSphere interfaces.
*/
public class WebsphereUtil {
private static HashMap cache = new HashMap();
private static Log log = LogFactory.getLog("WebSphereUtil");
// WAS doesn't expose these anywhere we've found yet
private static final String TRUST_STORE = "javax.net.ssl.trustStore";
private static final String KEY_STORE = "javax.net.ssl.keyStore";
private static final String TRUST_STORE_PWD = "javax.net.ssl.trustStorePassword";
private static final String KEY_STORE_PWD = "javax.net.ssl.keyStorePassword";
private static final HashMap beans = new HashMap();
public static Object getRemoteMBeanValue(Metric metric)
throws MetricNotFoundException,
MetricUnreachableException,
PluginException {
return getRemoteMBeanValue(metric, metric.getAttributeName());
}
public static Object getRemoteMBeanValue(Metric metric, String attributeName)
throws MetricNotFoundException,
MetricUnreachableException,
PluginException {
AdminClient mServer = getMBeanServer(metric);
ObjectName objName;
try {
objName = new ObjectName(metric.getObjectName());
} catch (MalformedObjectNameException e) {
throw new MetricInvalidException(e.getMessage(), e);
}
try {
return mServer.getAttribute(objName,
metric.getAttributeName());
} catch (MBeanException e) {
String msg = "MBeanException: " + e.getMessage();
throw new PluginException(msg, e);
} catch (AttributeNotFoundException e) {
String msg = "Attribute '" + attributeName + "' "
+ "not found for '" + objName + "'";
throw new MetricNotFoundException(msg, e);
} catch (InstanceNotFoundException e) {
String msg = "MBean '" + objName + "' not found";
throw new MetricNotFoundException(msg, e);
} catch (ReflectionException e) {
String msg = "ReflectionException: " + e.getMessage();
throw new PluginException(msg, e);
} catch (ConnectorException e) {
String msg = "ConnectorException: " + e.getMessage();
throw new PluginException(msg, e);
}
}
//XXX cache
public static AdminClient getMBeanServer(Properties cfg)
throws MetricUnreachableException {
Properties props = getAdminProperties(cfg);
if (log.isDebugEnabled()) {
log.debug("Attempting to create admin client with props "
+ props + " from config " + cfg);
}
AdminClient mServer;
WebsphereStopWatch timer = new WebsphereStopWatch();
// http://blogs.sun.com/sunabl/entry/websphere_application_server_and_jvm ????
// XXX test it with solaris version.
try {
mServer = AdminClientFactory.createAdminClient(props);
} catch (LinkageError e) {
log.error("Incorrect JVM ??? !!!", e);
throw new MetricUnreachableException(e.getMessage(), e);
} catch (ConnectorException ex) {
Throwable e = ex;
while ((e = (Throwable) e.getCause()) != null) {
if (e instanceof LinkageError) {
throw new MetricUnreachableException("!!! Incorrect JVM !!!", e);
}
}
throw new MetricUnreachableException(ex.getMessage(), ex);
}
if (log.isDebugEnabled() && timer.isTooLong()) {
log.debug("createAdminClient took: "
+ timer.getElapsedSeconds() + " seconds");
}
return mServer;
}
public static Properties getAdminProperties(Properties cfg) {
log.debug("[getAdminProperties] cfg=" + cfg);
String host =
cfg.getProperty(WebsphereProductPlugin.PROP_ADMIN_HOST,
"localhost");
String port =
cfg.getProperty(WebsphereProductPlugin.PROP_ADMIN_PORT,
"8880");
Properties props = new Properties();
props.setProperty(AdminClient.CONNECTOR_TYPE,
AdminClient.CONNECTOR_TYPE_SOAP);
props.setProperty(AdminClient.CONNECTOR_HOST, host);
props.setProperty(AdminClient.CONNECTOR_PORT, port);
String user = cfg.getProperty(AdminClient.USERNAME, "");
String pass = cfg.getProperty(AdminClient.PASSWORD, "");
// user and pass cannot be null because getProperty() is called
// with default values
if (!user.equals("") && !pass.equals("")) {
props.setProperty(AdminClient.USERNAME, user);
props.setProperty(AdminClient.PASSWORD, pass);
props.setProperty(AdminClient.CONNECTOR_SECURITY_ENABLED, "true");
// Set the ssl props, if they're available. As of this writing, there are no
// publicly-available constants for the prop keys, so they're kept in this source file.
String trustStore = cfg.getProperty(TRUST_STORE);
String keyStore = cfg.getProperty(KEY_STORE);
String trustStorePwd = cfg.getProperty(TRUST_STORE_PWD);
String keyStorePwd = cfg.getProperty(KEY_STORE_PWD);
if (trustStore != null && keyStore != null
&& trustStorePwd != null && keyStorePwd != null) {
props.setProperty(TRUST_STORE, trustStore);
props.setProperty(KEY_STORE, keyStore);
props.setProperty(TRUST_STORE_PWD, trustStorePwd);
props.setProperty(KEY_STORE_PWD, keyStorePwd);
}
}
log.debug("[getAdminProperties] props=" + props);
return props;
}
public static AdminClient getMBeanServer(Metric metric)
throws MetricUnreachableException {
String key = metric.getPropString();
AdminClient mServer =
(AdminClient) cache.get(key);
if (mServer != null) {
try {
mServer.getDomainName();
} catch (ConnectorException e) {
mServer = null;
log.debug("getMBeanServer stale connection: " + key);
}
}
if (mServer == null) {
mServer = getMBeanServer(metric.getProperties());
cache.put(key, mServer);
log.debug("getMBeanServer caching: " + key);
}
return mServer;
}
//only use this for 1 metric at the moment, to
//verify the admin server has been given proper
//configuration.
public static double getMBeanCount(AdminClient mServer,
ObjectName query,
String attr)
throws MetricUnreachableException,
MetricNotFoundException {
double count = 0;
try {
Set beansSet = mServer.queryNames(query, null);
for (Iterator it = beansSet.iterator(); it.hasNext();) {
ObjectName name = (ObjectName) it.next();
try {
if (attr != null) {
mServer.getAttribute(name, attr);
}
count++;
} catch (AttributeNotFoundException e) {
throw new MetricNotFoundException(name.toString());
} catch (InstanceNotFoundException e) {
throw new MetricNotFoundException(name.toString());
} catch (Exception e) {
//e.g. unauthorized
throw new MetricUnreachableException(name
+ ": " + e.getMessage(), e);
}
}
} catch (ConnectorException e) {
throw new MetricUnreachableException(query.toString(), e);
}
if (count == 0) {
throw new MetricNotFoundException(query
+ " (Invalid node name?)");
}
return count;
}
public static ObjectName resolve(AdminClient mServer, ObjectName name)
throws PluginException {
if (!name.isPattern()) {
return name;
}
log.debug("[resolve] name: " + name);
Set beansSet;
try {
beansSet = mServer.queryNames(name, null);
} catch (ConnectorException e) {
String msg = "[resolve] name:" + name + " error: " + e.getMessage();
throw new PluginException(msg, e);
}
for (Object object : beansSet) {
log.debug("[resolve] object found: " + object);
}
if (beansSet.size() != 1) {
String msg = name + " query returned " + beansSet.size() + " results";
throw new PluginException(msg);
}
ObjectName fullName = (ObjectName) beansSet.iterator().next();
if (log.isDebugEnabled()) {
log.debug(name + " resolved to: " + fullName);
}
return fullName;
}
public static boolean isRunning(Metric metric) {
//for the moment avail == 1 MBean is registered.
AdminClient mServer;
String domain;
try {
mServer = getMBeanServer(metric);
domain = mServer.getDomainName();
} catch (MetricUnreachableException e) {
log.debug(metric + ": " + e, e);
return false;
} catch (ConnectorException e) {
log.debug(metric + ": " + e, e);
return false;
}
String query =
domain + ":"
+ metric.getObjectPropString() + ",*";
ObjectName name = (ObjectName) beans.get(query);
if (name == null) {
try {
name = new ObjectName(query);
} catch (MalformedObjectNameException e) {
throw new MetricInvalidException(metric.getObjectName());
}
try {
name = resolve(mServer, name);
} catch (PluginException e) {
return false;
}
log.debug("isRunningCache " + query + "-->" + name);
beans.put(query, name);
return true;
}
try {
mServer.getMBeanInfo(name);
return true;
} catch (Exception e) {
beans.remove(query);
return false;
}
}
/**
* Wrapper around javax.management.MBeanServer.invoke
*
* @param objectName Used to construct a javax.management.ObjectName which
* is required by MBeanServer.invoke
* @param props Properties for the AdminClient connection, defined by
* WebsphereProductPlugin.getConfigSchema.
* @param method Name of the method to invoke on the server.
* @param args Arguments passed to MBeanServer.invoke
* @param sig Argument signatures passed to MBeanServer.invoke
* @throws PluginException on any error.
*/
public static Object invoke(String objectName,
Properties props,
String method,
Object[] args, String[] sig)
throws PluginException {
AdminClient mServer;
try {
mServer = getMBeanServer(props);
} catch (MetricUnreachableException e) {
throw new PluginException(e.getMessage(), e);
}
return invoke(mServer, objectName, method, args, sig);
}
public static Object invoke(AdminClient mServer,
String objectName,
String method,
Object[] args, String[] sig)
throws PluginException {
ObjectName obj;
try {
obj = new ObjectName(objectName);
} catch (MalformedObjectNameException e) {
throw new PluginException(e);
}
try {
if (obj.isPattern()) {
obj = resolve(mServer, obj);
}
return mServer.invoke(obj, method, args, sig);
} catch (InstanceNotFoundException e) {
throw new PluginException(e.getMessage(), e);
} catch (MBeanException e) {
throw new PluginException(e.getMessage(), e);
} catch (ReflectionException e) {
throw new PluginException(e.getMessage(), e);
} catch (ConnectorException e) {
throw new PluginException(e.getMessage(), e);
} catch (IllegalArgumentException e) {
throw new PluginException(e.getMessage(), e);
}
}
}