/*
* 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.pmi.PmiConstants;
import com.ibm.websphere.pmi.PmiException;
import com.ibm.websphere.pmi.client.CpdCollection;
import com.ibm.websphere.pmi.client.CpdData;
import com.ibm.websphere.pmi.client.CpdLoad;
import com.ibm.websphere.pmi.client.CpdStat;
import com.ibm.websphere.pmi.client.CpdValue;
import com.ibm.websphere.pmi.client.PerfDescriptor;
import com.ibm.websphere.pmi.client.PmiClient;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Properties;
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;
/**
* map a Metric to the WebSphere PMI api.
*/
public class WebspherePMI {
private static HashMap clientCache = new HashMap();
private static HashMap descriptorCache = new HashMap();
static class CpdCache {
int expire = 1000 * 60 * 10;
long timestamp = 0;
CpdCollection value = null;
}
static class PmiClientWrapper extends PmiClient {
HashMap cache = new HashMap();
public PmiClientWrapper() throws RemoteException {
super();
}
public PmiClientWrapper(String arg0, String arg1, String arg2)
throws RemoteException {
super(arg0, arg1, arg2);
}
public PmiClientWrapper(Properties arg0, String arg1)
throws RemoteException {
super(arg0, arg1);
}
public CpdCollection get(Metric metric, PerfDescriptor desc)
throws PmiException {
long timeNow = System.currentTimeMillis();
String key = metric.getObjectName();
CpdCache cacheValue = (CpdCache) cache.get(key);
if (cacheValue == null) {
cacheValue = new CpdCache();
cache.put(key, cacheValue);
} else if ((timeNow - cacheValue.timestamp) > cacheValue.expire) {
cacheValue.value = null;
}
if (cacheValue.value == null) {
cacheValue.timestamp = timeNow;
cacheValue.value = super.get(desc, false);
}
return cacheValue.value;
}
}
public static PmiClient getPmiClient(Properties cfg)
throws RemoteException {
Properties props = getAdminProperties(cfg);
return new PmiClientWrapper(props, "WAS50");
}
private static PmiClient getPmiClient(Metric metric)
throws RemoteException {
PmiClient pmiclient;
String key = metric.getPropString();
synchronized (clientCache) {
pmiclient = (PmiClient) clientCache.get(key);
}
if (pmiclient == null) {
pmiclient = getPmiClient(metric.getProperties());
synchronized (clientCache) {
clientCache.put(key, pmiclient);
}
}
return pmiclient;
}
public static PerfDescriptor getModuleDescriptor(PmiClient pmiclient,
Metric metric) {
String key = metric.getObjectName();
PerfDescriptor moduleDescriptor;
synchronized (descriptorCache) {
moduleDescriptor = (PerfDescriptor) descriptorCache.get(key);
}
if (moduleDescriptor == null) {
Properties props = metric.getObjectProperties();
PerfDescriptor serverDescriptor =
PmiClient.createPerfDescriptor(metric.getDomainName());
moduleDescriptor =
PmiClient.createPerfDescriptor(serverDescriptor,
props.getProperty("Module"));
synchronized (descriptorCache) {
descriptorCache.put(key, moduleDescriptor);
}
}
return moduleDescriptor;
}
//XXX plenty of optimizations can be made here.
public static Double getValue(Metric metric)
throws PluginException,
MetricNotFoundException,
MetricUnreachableException {
//XXX for the moment, if there is a module descriptor for the
//server/service it is considered available. this will remain
//the case for certain services such as EJB, JDBC and Thread Pools
//others such as server and webapp should have more robust checks.
boolean isAvail = metric.isAvail();
PmiClientWrapper pmiclient;
try {
pmiclient = (PmiClientWrapper) getPmiClient(metric);
} catch (RemoteException e) {
if (isAvail) {
return new Double(Metric.AVAIL_DOWN);
}
Properties props = metric.getProperties();
String msg = "Cannot connect to server "
+ props.getProperty(WebsphereProductPlugin.PROP_ADMIN_HOST)
+ ":"
+ props.getProperty(WebsphereProductPlugin.PROP_ADMIN_PORT);
String rmsg = e.getMessage();
if (rmsg.indexOf("\n") < 0) {
msg += " (" + rmsg + ")";
} //else is a bigass stacktrace
throw new MetricUnreachableException(msg, e);
}
CpdCollection stats;
synchronized (pmiclient) {
PerfDescriptor moduleDescriptor =
getModuleDescriptor(pmiclient, metric);
try {
stats = pmiclient.get(metric, moduleDescriptor);
} catch (PmiException pe) {
String msg = "Error getting " + metric.getObjectName();
throw new PluginException(msg, pe);
}
}
boolean haveStats =
((stats != null)
&& (stats.dataMembers() != null)
&& (stats.dataMembers().length > 0));
if (isAvail) {
if (haveStats) {
//if the server can collect stats, then the service
//is considered available.
return new Double(Metric.AVAIL_UP);
} else {
return new Double(Metric.AVAIL_DOWN);
}
}
CpdData data = null;
if (haveStats) {
data = findCpdData(stats.dataMembers(),
metric.getAttributeName());
}
if (data == null) {
String obj = metric.getObjectPropString();
if (!obj.equals("Module=jvmRuntimeModule") && //jvm must be present
obj.startsWith("Module=") && obj.endsWith("Module")) //aggregates
{
//can happen if no services are deployed for
//the given type:
//Module={connectionPool,servletSessions,transaction,etc}Module
return new Double(Double.NaN);
}
throw new MetricNotFoundException(metric.getObjectName());
}
CpdValue value = data.getValue();
switch (value.getType()) {
case PmiConstants.TYPE_STAT:
CpdStat cpdstat = (CpdStat) value;
return new Double(cpdstat.getValue());
case PmiConstants.TYPE_LOAD:
CpdLoad cpdload = (CpdLoad) value;
return new Double(cpdload.getValue());
case PmiConstants.TYPE_LONG:
case PmiConstants.TYPE_DOUBLE:
case PmiConstants.TYPE_INT:
return new Double(value.getValue());
default:
throw new MetricInvalidException(metric.toString());
}
}
private static CpdData findCpdData(CpdData[] data, String name) {
String match = "." + name;
for (int i = 0; i < data.length; i++) {
if (data[i].getDescriptor().getName().endsWith(match)) {
return data[i];
}
}
return null;
}
public static Properties getAdminProperties(Properties 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, "");
if ((!"".equals(user)) && (!"".equals(pass))) {
props.setProperty(AdminClient.USERNAME, user);
props.setProperty(AdminClient.PASSWORD, pass);
props.setProperty(AdminClient.CONNECTOR_SECURITY_ENABLED, "true");
}
return props;
}
}