/*
* 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.jboss;
import java.io.File;
import java.rmi.RemoteException;
import javax.naming.NamingException;
import org.hyperic.hq.product.Metric;
import org.hyperic.hq.product.MetricNotFoundException;
import org.hyperic.hq.product.MetricUnreachableException;
import org.hyperic.hq.product.ServerControlPlugin;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.TypeInfo;
import org.hyperic.util.StringUtil;
import org.hyperic.util.config.ConfigOption;
import org.hyperic.util.config.ConfigSchema;
import org.hyperic.util.config.ConfigResponse;
public class JBossServerControlPlugin extends ServerControlPlugin {
// JBoss server control timeout defaults to 10 minutes
protected static final int TIMEOUT = 10 * 60;
public static final String PROP_CONFIGSET = "configSet";
static final String PROP_STOP_PROGRAM = "stop.program";
static final String PROP_STOP_ARGS = "stop.args";
static final String PROP_START_ARGS = "start.args";
private static final String SERVER = "jboss.system:type=Server";
private String configSet = null;
private Metric serverMetric = null;
//flag == true if we are doing stop action using a program
//rather than JMX
private boolean isStopProgramAction = false;
public JBossServerControlPlugin() {
super();
//give waitForState enough time
setTimeout(TIMEOUT);
}
@Override
public void configure(ConfigResponse config)
throws PluginException {
super.configure(config);
String val = config.getValue(PROP_CONFIGSET);
if (val != null) {
this.configSet = val;
}
else {
getLog().error("Can't find server name in config response " +
config);
throw new PluginException("no server name configured");
}
}
private Metric configureMetric(String template) {
String metric = Metric.translate(template, getConfig());
try {
return Metric.parse(metric); //parsing will be cached
} catch (Exception e) {
getLog().error("Metric parsing error: " + e.getMessage(), e);
return null;
}
}
private String getConfigSet() {
return this.configSet;
}
private Metric getServerMetric() {
if (this.serverMetric == null) {
String metric =
SERVER + ":Version:" +
getPluginProperty(JBossMeasurementPlugin.PROP_TEMPLATE_CONFIG);
this.serverMetric = configureMetric(metric);
}
return this.serverMetric;
}
@Override
protected boolean isRunning() {
try {
JBossUtil.getMBeanServerConnection(getConfig().toProperties());
return true;
} catch (NamingException e) {
return false;
} catch (RemoteException e) {
return false;
}
}
@Override
protected File getWorkingDirectory() {
return new File(getInstallPrefix(), "bin");
}
@Override
protected boolean isBackgroundCommand() {
return !this.isStopProgramAction;
}
static String getControlScript(boolean isWin32) {
String sep, ext;
if (isWin32) {
sep = "\\";
ext = "bat";
}
else {
sep = "/";
ext = "sh";
}
return "bin" + sep + "run." + ext;
}
@Override
protected void getServerConfigSchema(TypeInfo info,
ConfigSchema schema,
ConfigResponse response) {
boolean isWin32 = getTypeInfo().isWin32Platform();
//relative to installpath
setControlProgram(getControlScript(isWin32));
super.getServerConfigSchema(info, schema, response);
String installpath =
response.getValue(ProductPlugin.PROP_INSTALLPATH,
getDefaultInstallPath());
String sep = isWin32 ? "\\" : "/";
//strip "servers/default"
//cannot use java.io.File, will convert pathSep
//if agent is linux and server is win32
int ix = installpath.lastIndexOf(sep);
if (ix != -1) {
String servers = installpath.substring(0, ix);
final String tok = sep + "servers";
if (servers.endsWith(tok)) {
installpath =
servers.substring(0, servers.length() - tok.length());
}
}
schema.setDefault(PROP_PROGRAM,
installpath + sep + getControlProgram());
}
@Override
public ConfigSchema getConfigSchema(TypeInfo info, ConfigResponse config) {
//XXX re-order for UI display
ConfigSchema schema = super.getConfigSchema(info, config);
ConfigOption opt = schema.getOption(PROP_PROGRAM);
opt.setDescription("Server start program");
schema.addOptionAsFirst(opt);
return schema;
}
@Override
protected String[] getCommandEnv() {
return new String[] {
"JBOSS_HOME=" + getJBossHome(),
"NOPAUSE=true",
};
}
// Check for branded server.
private boolean isBrandedServer() {
if (JBossProductPlugin.isBrandedServer(new File(getInstallPrefix()),
getPluginProperty("brand.ear")))
{
setResult(RESULT_FAILURE);
setMessage("Control not supported for " +
getPluginProperty("brand.name"));
return true;
}
return false;
}
// control methods
private String[] getProgramArgs(String prop) {
String cmdline = getConfig(prop);
if ((cmdline == null) || (cmdline.length() == 0)) {
return null;
}
return StringUtil.explodeQuoted(cmdline);
}
public void start() {
if (isBrandedServer()) {
return;
}
String[] args = getProgramArgs(PROP_START_ARGS);
if (args == null) {
String _config = getConfigSet();
if ((_config == null) || (_config.length() == 0)) {
args = new String[0];
}
else {
args = new String[] { "-c", _config };
}
}
doCommand(getControlProgram(), args);
handleResult(STATE_STARTED);
}
public void stop() {
if (isBrandedServer()) {
return;
}
String program = getConfig(PROP_STOP_PROGRAM);
if ((program == null) || (program.length() == 0)) {
invokeMethod("shutdown");
if (getResult() == RESULT_SUCCESS) {
setMessage("Server stopped via JMX");
}
}
else {
String cmdline = getConfig(PROP_STOP_ARGS);
String[] args = StringUtil.explodeQuoted(cmdline);
this.isStopProgramAction = true;
try {
doCommand(program, args);
} finally {
//reset for start control
this.isStopProgramAction = false;
}
}
handleResult(STATE_STOPPED);
}
public void restart() {
if (isBrandedServer()) {
return;
}
boolean hadToStop = false;
if (isRunning()) {
hadToStop = true;
stop();
}
if (!hadToStop || (getResult() == RESULT_SUCCESS)) {
start();
}
}
public void runGarbageCollector() {
invokeMethod("runGarbageCollector");
}
private void invokeMethod(String action) {
try {
JBossUtil.invoke(getServerMetric(), action);
setResult(RESULT_SUCCESS);
} catch (MetricNotFoundException e) {
setMessage(e.getMessage());
setResult(RESULT_FAILURE);
} catch (MetricUnreachableException e) {
setMessage(e.getMessage());
setResult(RESULT_FAILURE);
} catch (PluginException e) {
if (action.equals("shutdown") &&
! isRunning()) {
// might get nested java.net.SocketException:
// Connection reset which is ok/expected-ish if we are
// stopping the server.
setResult(RESULT_SUCCESS);
}
else {
setMessage(e.getMessage());
setResult(RESULT_FAILURE);
}
}
}
private String getJBossHome() {
File server = new File(getInstallPrefix());
File home = server.getParentFile().getParentFile();
return home.getPath();
}
}