// NAnt - A .NET build tool
// Copyright (C) 2001-2004 Gert Driesen
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// 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
//
// Gert Driesen (gert.driesen@ardatis.com)
// Giuseppe Greco (giuseppe.greco@agamura.com)
using System;
using System.ComponentModel;
using System.Globalization;
using System.ServiceProcess;
using NAnt.Core;
using NAnt.Core.Attributes;
using NAnt.Core.Util;
namespace NAnt.MSNet.Tasks {
///
/// Allows a Windows service to be controlled.
///
///
/// Starts the World Wide Web Publishing Service on the local computer.
///
///
/// ]]>
///
///
///
/// Stops the Alerter service on computer 'MOTHER'.
///
///
/// ]]>
///
///
[TaskName("servicecontroller")]
public class ServiceControllerTask : Task {
///
/// Defines the actions that can be performed on a service.
///
public enum ActionType {
///
/// Starts a service.
///
Start,
///
/// Stops a service.
///
Stop,
///
/// Restarts a service.
///
Restart,
///
/// Pauses a running service.
///
Pause,
///
/// Continues a paused service.
///
Continue
}
#region Public Instance Constructors
///
/// Initializes a new instance of the
/// class.
///
public ServiceControllerTask() {
}
#endregion Public Instance Constructors
#region Public Instance Properties
///
/// The name of the service that should be controlled.
///
[TaskAttribute("service", Required=true)]
[StringValidator(AllowEmpty=false)]
public string ServiceName {
get { return _serviceName; }
set { _serviceName = StringUtils.ConvertEmptyToNull(value); }
}
///
/// The name of the computer on which the service resides. The default
/// is the local computer.
///
[TaskAttribute("machine")]
public string MachineName {
get { return (_machineName == null) ? "." : _machineName; }
set { _machineName = StringUtils.ConvertEmptyToNull(value); }
}
///
/// The action that should be performed on the service.
///
[TaskAttribute("action", Required=true)]
public ActionType Action {
get { return _action; }
set { _action = value; }
}
///
/// The time, in milliseconds, the task will wait for the service to
/// reach the desired status. The default is 5000 milliseconds.
///
[TaskAttribute("timeout", Required=false)]
public double Timeout {
get { return _timeout; }
set { _timeout = value; }
}
#endregion Public Instance Properties
#region Override implementation of Task
///
/// Peforms actions on the service in order to reach the desired status.
///
protected override void ExecuteTask() {
// get handle to service
using (ServiceController serviceController = new ServiceController(ServiceName, MachineName)) {
// determine desired status
ServiceControllerStatus desiredStatus = DetermineDesiredStatus();
try {
// determine current status, this is also verifies if the service
// is available
ServiceControllerStatus currentStatus = serviceController.Status;
} catch (Exception ex) {
throw new BuildException(ex.Message, Location, ex.InnerException);
}
// we only need to take action if the service status differs from
// the desired status or if the service should be restarted
if (serviceController.Status != desiredStatus || Action == ActionType.Restart) {
switch (Action) {
case ActionType.Start:
StartService(serviceController);
break;
case ActionType.Pause:
PauseService(serviceController);
break;
case ActionType.Continue:
ContinueService(serviceController);
break;
case ActionType.Stop:
StopService(serviceController);
break;
case ActionType.Restart:
RestartService(serviceController);
break;
}
// refresh current service status
serviceController.Refresh();
}
}
}
#endregion Override implementation of Task
#region Private Instance Methods
///
/// Determines the desired status of the service based on the action
/// that should be performed on it.
///
///
/// The that should be reached
/// in order for the to be considered successful.
///
private ServiceControllerStatus DetermineDesiredStatus() {
switch (Action) {
case ActionType.Stop:
return ServiceControllerStatus.Stopped;
case ActionType.Pause:
return ServiceControllerStatus.Paused;
default:
return ServiceControllerStatus.Running;
}
}
///
/// Starts the service identified by and
/// .
///
/// instance for controlling the service identified by and .
private void StartService(ServiceController serviceController) {
try {
if (serviceController.Status == ServiceControllerStatus.Paused) {
serviceController.Continue();
} else {
serviceController.Start();
}
// wait until service is running or timeout expired
serviceController.WaitForStatus(ServiceControllerStatus.Running,
TimeSpan.FromMilliseconds(Timeout));
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3007"), ServiceName, MachineName), Location, ex);
}
}
///
/// Stops the service identified by and
/// .
///
/// instance for controlling the service identified by and .
private void StopService(ServiceController serviceController) {
try {
if (serviceController.CanStop) {
serviceController.Stop();
} else {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3008"), ServiceName, MachineName), Location);
}
// wait until service is stopped or timeout expired
serviceController.WaitForStatus(ServiceControllerStatus.Stopped,
TimeSpan.FromMilliseconds(Timeout));
} catch (BuildException ex) {
// rethrow exception
throw ex;
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3008"), ServiceName, MachineName), Location, ex);
}
}
///
/// Restarts the service identified by and
/// .
///
/// instance for controlling the service identified by and .
private void RestartService(ServiceController serviceController) {
// only stop service if its not already stopped
if (serviceController.Status != ServiceControllerStatus.Stopped) {
StopService(serviceController);
}
// start the service
StartService(serviceController);
}
///
/// Pauses the service identified by and
/// .
///
/// instance for controlling the service identified by and .
private void PauseService(ServiceController serviceController) {
try {
if (serviceController.Status == ServiceControllerStatus.Running) {
if (serviceController.CanPauseAndContinue) {
if (serviceController.Status != ServiceControllerStatus.Running) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3010"), ServiceName, MachineName),
Location);
} else {
serviceController.Pause();
}
} else {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3011"), ServiceName, MachineName),
Location);
}
} else {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3010"), ServiceName, MachineName),
Location);
}
// wait until service is paused or timeout expired
serviceController.WaitForStatus(ServiceControllerStatus.Paused,
TimeSpan.FromMilliseconds(Timeout));
} catch (BuildException ex) {
// rethrow exception
throw ex;
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3009"), ServiceName, MachineName),
Location, ex);
}
}
///
/// Continues the service identified by and
/// .
///
/// instance for controlling the service identified by and .
private void ContinueService(ServiceController serviceController) {
try {
if (serviceController.Status == ServiceControllerStatus.Paused) {
if (serviceController.CanPauseAndContinue) {
if (serviceController.Status == ServiceControllerStatus.Paused) {
serviceController.Continue();
} else if (serviceController.Status != ServiceControllerStatus.Running) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3013"), ServiceName, MachineName),
Location);
} else {
// do nothing as service is already running
}
} else {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3014"), ServiceName, MachineName),
Location);
}
} else {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3015"), ServiceName, MachineName),
Location);
}
// wait until service is running or timeout expired
serviceController.WaitForStatus(ServiceControllerStatus.Running,
TimeSpan.FromMilliseconds(Timeout));
} catch (BuildException ex) {
// rethrow exception
throw ex;
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA3012"), ServiceName, MachineName),
Location, ex);
}
}
#endregion Private Instance Methods
#region Private Instance Fields
///
/// Holds the name of the service that should be controlled.
///
private string _serviceName;
///
/// Holds the name of the computer on which the service resides.
///
private string _machineName;
///
/// Holds the action that should be performed on the service.
///
private ActionType _action;
///
/// Holds the time, in milliseconds, the task will wait for a service
/// to reach the desired status.
///
private double _timeout = 5000;
#endregion Private Instance Fields
}
}