/*
* 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 java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.plugin.websphere.jmx.WebsphereRuntimeDiscoverer;
import org.hyperic.hq.product.AutoServerDetector;
import org.hyperic.hq.product.FileServerDetector;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.RegistryServerDetector;
import org.hyperic.hq.product.ServerControlPlugin;
import org.hyperic.hq.product.ServerDetector;
import org.hyperic.hq.product.ServerResource;
import org.hyperic.sigar.win32.RegistryKey;
import org.hyperic.util.config.ConfigResponse;
public class WebsphereDetector
extends ServerDetector
implements FileServerDetector,
RegistryServerDetector,
AutoServerDetector {
private static final String[] METRIC_CONNECT_PROPS = {
WebsphereProductPlugin.PROP_ADMIN_PORT,
WebsphereProductPlugin.PROP_ADMIN_HOST
};
static protected Log log =
LogFactory.getLog(WebsphereDetector.class.getName());
private static final String PTQL_QUERY =
"State.Name.eq=java,Args.*.eq=com.ibm.ws.runtime.WsServer";
private static final String SOAP_PORT_EXPR =
"//serverEntries[@serverName=\"{0}\"]//specialEndpoints[@endPointName=\"SOAP_CONNECTOR_ADDRESS\"]//@port";
private static final String SOAP_HOST_EXPR =
"//serverEntries[@serverName=\"{0}\"]//specialEndpoints[@endPointName=\"SOAP_CONNECTOR_ADDRESS\"]//@host";
protected WebsphereRuntimeDiscoverer discoverer = null;
private String node = null;
@Override
protected List discoverServices(ConfigResponse config) throws PluginException {
if (!WebsphereProductPlugin.VALID_JVM) {
return new ArrayList();
}
if (this.discoverer == null) {
String version = getTypeInfo().getVersion();
this.discoverer = new WebsphereRuntimeDiscoverer(version, this);
}
return this.discoverer.discoverServices(config);
}
protected String getProcessQuery() {
return PTQL_QUERY;
}
public String getAdminHost(WebSphereProcess proc) {
return getAdminHost(findServerIndex(proc), proc.getServer());
}
public String getAdminHost(File index, String serverName) {
String host = null;
final String prop = WebsphereProductPlugin.PROP_ADMIN_HOST;
Object[] servers = {serverName};
if (index != null) {
host = getXPathValue(index, MessageFormat.format(SOAP_HOST_EXPR, servers));
getLog().debug("Configuring " + prop + "=" + host + " from: " + index);
}
if (host == null) {
host = getManager().getProperty(prop, "localhost");
}
if (host.equals("*")) {
host = "localhost";
}
return host;
}
private File findServerIndex(WebSphereProcess proc) {
if (proc == null) {
return null;
}
File index = new File(proc.getServerRoot() + "/config/cells/" + proc.getCell() + "/nodes/" + proc.getNode() + "/serverindex.xml");
if (!index.exists()) {
index = null;
}
return index;
}
public String getAdminPort(WebSphereProcess proc) {
return getAdminPort(findServerIndex(proc), proc.getServer());
}
public String getAdminPort(File index, String serverName) {
String port = null;
final String prop = WebsphereProductPlugin.PROP_ADMIN_PORT;
Object[] servers = {serverName};
if (index != null) {
String query = MessageFormat.format(SOAP_PORT_EXPR, servers);
port = getXPathValue(index, query);
getLog().debug("Configuring " + prop + "=" + port + " from: " + index);
}
return port;
}
protected String getNodeName() {
return this.node;
}
public final String getControlScript(String script) {
return "bin" + File.separatorChar + script + getScriptExtension();
}
public final ConfigResponse getControlConfig(WebSphereProcess proc) {
String type = proc.getServer().equals("nodeagent") ? "Node" : "Server";
File cs1 = new File(proc.getServerRoot(), getControlScript("start" + type));
File cs2 = new File(proc.getServerRoot(), getControlScript("stop" + type));
assert cs1.exists() : cs1.getAbsolutePath();
assert cs2.exists() : cs2.getAbsolutePath();
ConfigResponse cc = new ConfigResponse();
cc.setValue(ServerControlPlugin.PROP_PROGRAM + ".start", cs1.getAbsolutePath());
cc.setValue(ServerControlPlugin.PROP_PROGRAM + ".stop", cs2.getAbsolutePath());
log.debug("[getControlConfig] server=" + proc.getServer());
log.debug("[getControlConfig] cc=" + cc);
return cc;
}
protected void initDetector(File root) {
//sadly, the setupCmdLine script is the
//best way to determine the node name
final String NODE_PROP = "WAS_NODE=";
File cmdline =
new File(root, "bin/setupCmdLine"
+ getScriptExtension());
Reader reader = null;
try {
reader = new FileReader(cmdline);
BufferedReader buffer =
new BufferedReader(reader);
String line;
while ((line = buffer.readLine()) != null) {
line = line.trim();
if (line.length() == 0) {
continue;
}
int ix = line.indexOf(NODE_PROP);
if (ix == -1) {
continue;
}
this.node =
line.substring(ix + NODE_PROP.length());
break;
}
} catch (IOException e) {
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
}
public static String getRunningInstallPath() {
return getRunningInstallPath(PTQL_QUERY);
}
static List getServerProcessList() {
return getServerProcessList(PTQL_QUERY);
}
protected Properties loadProps(File file) {
Properties props = new Properties();
FileInputStream is = null;
try {
is = new FileInputStream(file);
props.load(is);
} catch (IOException e) {
//ok
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
return props;
}
protected String getNodeNameFromFQDN(String fqdn) {
int idx = fqdn.indexOf(".");
if (idx > 0) {
return fqdn.substring(0, idx);
}
return fqdn;
}
protected Properties getProductConfig(WebSphereProcess proc) {
Properties productProps = new Properties();
productProps.setProperty(WebsphereProductPlugin.PROP_ADMIN_HOST,
getAdminHost(proc));
productProps.setProperty(WebsphereProductPlugin.PROP_ADMIN_PORT,
getAdminPort(proc));
productProps.setProperty(WebsphereProductPlugin.PROP_SERVER_NODE, proc.getNode());
productProps.setProperty(WebsphereProductPlugin.PROP_SERVER_CELL, proc.getCell());
productProps.setProperty(WebsphereProductPlugin.PROP_SERVER_NAME, proc.getServer());
return productProps;
}
protected boolean isServiceControl() {
return isWin32();
}
protected static List getServerProcessList(String query) {
final String wasProp = "-Dwas.install.root=";
final String rootProp = "-Dserver.root="; //5.x, optional in 6.1
ArrayList servers = new ArrayList();
long[] pids = getPids(query);
for (int i = 0; i < pids.length; i++) {
String[] args = getProcArgs(pids[i]);
WebSphereProcess process = new WebSphereProcess();
process.setPid(pids[i]);
// next-to-last arg should be node name
int ai = args.length;
if (args[ai - 1].trim().equals("")) {
ai--; // some times the las arg is a " "
}
if (args.length > 3) {
process.setServer(args[ai - 1]);
process.setNode(args[ai - 2]);
process.setCell(args[ai - 3]);
}
for (int j = 0; j < args.length; j++) {
String arg = args[j];
if (arg.startsWith(wasProp)) {
process.setInstallRoot(arg.substring(wasProp.length(), arg.length()));
} else if (arg.startsWith(rootProp)) {
process.setServerRoot(arg.substring(rootProp.length(), arg.length()));
}
if (process.isPropsConfigured()) {
log.debug("[getServerProcessList] process=" + process);
servers.add(process);
break;
}
}
}
return servers;
}
protected static String getRunningInstallPath(String query) {
List servers = getServerProcessList(query);
if (servers.size() == 0) {
return null;
}
return ((WebSphereProcess) servers.get(0)).getInstallRoot();
}
//used for 6.0 and 6.1
static final String VERSION_START = "<version>";
static final String VERSION_END = "</version>";
protected static String getComponentVersion(File file) {
Reader reader = null;
String res = "";
try {
reader = new FileReader(file);
BufferedReader buffer = new BufferedReader(reader);
String line;
while ((line = buffer.readLine()) != null) {
line = line.trim();
int ix = line.indexOf(VERSION_END);
if (line.startsWith(VERSION_START) && (ix != -1)) {
res = line.substring(VERSION_START.length(), ix).trim();
}
}
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.error("Error getting the WAS version: " + e.getMessage(), e);
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
return res;
}
protected boolean isComponentVersion(File file) {
String version = getComponentVersion(file);
boolean res = version.startsWith(getTypeInfo().getVersion());
log.debug("version= '" + version + "' type='" + getTypeInfo().getVersion() + "' res=" + res);
return res;
}
protected List getServerList(File serverDir, String version, WebSphereProcess proc)
throws PluginException {
log.debug("[getServerList] (" + version + ") " + proc.getInstallRoot());
List servers = new ArrayList();
//make sure detector version is that of was version
//else the 5.0 detector will report 6.0 servers
if (version != null) {
char majVersion =
getTypeInfo().getVersion().charAt(0);
if (version.charAt(0) != majVersion) {
return null;
}
}
//distinquish between versions using a unique file
//since there is no simple way to get the version on disk.
String uniqueFile =
getTypeProperty("UNIQUE_FILE");
if (uniqueFile != null) {
File file = new File(proc.getInstallRoot(), uniqueFile);
boolean exists = file.exists();
log.debug(getTypeInfo().getName() + " '"
+ file + "'.exists()=" + exists);
if (!exists) {
return null;
}
if (file.getName().equals("WAS.product")) {
if (!isComponentVersion(file)) {
return null;
}
}
}
initDetector(serverDir);
String installpath = serverDir.getAbsolutePath();
ServerResource server = createServerResource(installpath);
String type = getTypeInfo().getName();
//for example, having WebSphere 6.0 and 6.1 installed
//on the same machine, use version in the name to make
//them unique.
if ((version != null) && (version.length() == 3)) {
if (!type.endsWith(version)) {
type = type.substring(0, type.length() - 3) + version;
}
}
server.setIdentifier(proc.getIdentifier());
server.setName(getPlatformName() + " " + type + " " + proc.getServerName());
ConfigResponse productConfig =
new ConfigResponse(getProductConfig(proc));
populateListeningPorts(proc.getPid(), productConfig, true);
if (WebsphereProductPlugin.isOSGi()) {
String prop = WebsphereProductPlugin.PROP_INSTALL_ROOT;
String root =
System.getProperty(prop, getTypeProperty(prop));
if (root != null) {
productConfig.setValue(prop, root);
}
}
//if we find more than one server w/ the same connect config,
//this will make sure only 1 gets auto-enabled for metrics/ai
server.setConnectProperties(METRIC_CONNECT_PROPS);
setProductConfig(server, productConfig);
server.setMeasurementConfig();
setControlConfig(server, getControlConfig(proc));
servers.add(server);
log.debug("Detected " + server.getName() + " in " + serverDir);
return servers;
}
public List getServerResources(ConfigResponse platformConfig, String path, RegistryKey current)
throws PluginException {
path = path.trim(); //trim trailing ^@
log.debug("checking path=" + path);
String version = current.getSubKeyName();
//5.0.0.0, 5.1.0.0, etc.
if ((version != null) && (version.length() > 3)) {
version = version.trim().substring(0, 3);
}
return getServerList(new File(path), version, null);
}
public List getServerResources(ConfigResponse platformConfig) throws PluginException {
List servers = new ArrayList();
List processes = getServerProcessList(getProcessQuery());
for (int i = 0; i < processes.size(); i++) {
WebSphereProcess p = (WebSphereProcess) processes.get(i);
if (!p.getServer().equals("nodeagent")) {
String nodeAgentPort = getAdminPort(findServerIndex(p), "nodeagent"); // skip if has nodeagent?
if (nodeAgentPort == null) {
List found = getServerList(new File(p.getServerRoot()), null, p);
if (found != null) {
servers.addAll(found);
}
}
}
}
return servers;
}
public List getServerResources(ConfigResponse platformConfig, String path)
throws PluginException {
log.debug("Looking for " + getName() + " in " + path);
File jar = new File(path);
//loose lib/foo.jar defined in etc/cam-server-sigs.properties
File serverDir = jar.getParentFile().getParentFile();
return getServerList(serverDir, null, null);
}
private void populateListeningPorts(long pid, ConfigResponse productConfig, boolean b) {
try {
Class du = Class.forName("org.hyperic.hq.product.DetectionUtil");
Method plp = du.getMethod("populateListeningPorts", long.class, ConfigResponse.class, boolean.class);
plp.invoke(null, pid, productConfig, b);
} catch (ClassNotFoundException ex) {
log.debug("[populateListeningPorts] Class 'DetectionUtil' not found", ex);
} catch (NoSuchMethodException ex) {
log.debug("[populateListeningPorts] Method 'populateListeningPorts' not found", ex);
} catch (Exception ex) {
log.debug("[populateListeningPorts] Problem with Method 'populateListeningPorts'", ex);
}
}
}