/* * 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 java.util.Arrays; import java.util.List; import org.hyperic.util.config.ConfigResponse; import org.hyperic.hq.bizapp.shared.lather.ControlSendCommandResult_args; import org.hyperic.sigar.win32.Service; import org.hyperic.sigar.win32.Win32Exception; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Base class for control plugins. */ public class Win32ControlPlugin extends ControlPlugin { public static final String PROP_SERVICENAME = "service_name"; protected Log log; protected String serviceName = null; protected String installPrefix = null; protected Service svc; private static final String actions[] = { "start", "stop", "restart" }; private static final List commands = Arrays.asList(actions); public Win32ControlPlugin() { this.log = LogFactory.getLog(this.getClass().getName()); } protected Log getLog() { return this.log; } public String getServiceName() { return this.serviceName; } public void setServiceName(String val) { this.serviceName = val; } protected boolean isServiceRequired() { return true; } public String getInstallPrefix() { return this.installPrefix; } public void setInstallPrefix(String val) { this.installPrefix = val; } public void configure(ConfigResponse config) throws PluginException { super.configure(config); String val; // Check to see if the plugin defined the service name. If not, // then the plugin must have queried the user, so we will have to // check the configResponse. if ((val = getServiceName()) == null) { val = config.getValue(Win32ControlPlugin.PROP_SERVICENAME); if (val != null) { setServiceName(val); } } val = config.getValue(ProductPlugin.PROP_INSTALLPATH); if (val != null) { setInstallPrefix(val); } try { if (getServiceName() == null) { //XXX sigar should do this check throw new Win32Exception("Service name cannot be null"); } svc = new Service(getServiceName()); } catch (Win32Exception e) { String msg = "Could not open Windows Service: " + getServiceName(); if (isServiceRequired()) { throw new PluginException(msg); } else { log.debug(msg); } } } protected boolean isRunning() { return isRunning(this.svc); } protected boolean isRunning(Service service) { String resp = detectState(service); // This is kind of bogus, but Windows service's don't match // exactly to our model, so anything other than STOPPED or // UNKNOWN is running. if (resp.equals(STATE_STARTED) || resp.equals(STATE_STARTING) || resp.equals(STATE_STOPPING)) { return true; } else { return false; } } // We can't really return RESTARTING for a Windows service. The // problem is that all services have a different way of restarting, // and it isn't clear that the Service Manager return codes are // extensible. If a Windows service can return RESTARTING, it will // have to overload this method. To take Apache as an example, // during a restart Apache will return START_PENDING to the service // manager, so detectState will return STATE_STARTING. protected String detectState(Service service) { switch (service.getStatus()) { case Service.SERVICE_START_PENDING: return STATE_STARTING; case Service.SERVICE_STOPPED: return STATE_STOPPED; case Service.SERVICE_RUNNING: return STATE_STARTED; case Service.SERVICE_STOP_PENDING: return STATE_STOPPING; case Service.SERVICE_CONTINUE_PENDING: case Service.SERVICE_PAUSE_PENDING: case Service.SERVICE_PAUSED: return STATE_UNKNOWN; } return STATE_UNKNOWN; } protected String waitForState(String wantedState) { int timeout = getTimeoutMillis(); long timeStart = System.currentTimeMillis(); String state = detectState(); while (!state.equals(wantedState) && (System.currentTimeMillis() - timeStart) < timeout) { try { Thread.sleep(500); } catch (InterruptedException e) { // Ignore } state = detectState(); } return state; } public List getActions() { return commands; } public void doAction(String action) throws PluginException { try { if (action.equals("start")) { svc.start(); setResult(RESULT_SUCCESS); return; } if (action.equals("stop")) { svc.stop(); setResult(RESULT_SUCCESS); return; } if (action.equals("restart")) { if (isRunning()){ svc.stop((long)getTimeoutMillis()); } svc.start(); setResult(RESULT_SUCCESS); return; } } catch (Win32Exception e) { setResult(RESULT_FAILURE); throw new PluginException(action + " " + getServiceName() + " failed: " + e.getMessage()); } throw new PluginException("Action '" + action + "' not supported"); } }