blob: 20a9d87c622f23b73e5db44bcc2bee395c4ef288 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 SAS Institute, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Larry Isaacs - Initial API and implementation
*******************************************************************************/
package org.eclipse.jst.server.tomcat.ui.internal;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jst.server.core.IWebModule;
import org.eclipse.jst.server.tomcat.core.internal.ITomcatWebModule;
import org.eclipse.jst.server.tomcat.core.internal.TomcatServerBehaviour;
import org.eclipse.jst.server.tomcat.core.internal.WebModule;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.ServerUtil;
import org.eclipse.wst.server.core.IServer.IOperationListener;
/**
* Dialog to confirm deletion of the work directory for a module on a
* server, or the work directory for the entire server. Handling
* includes stopping and restarting the server if it is running at
* the time of the deletion.
*
*/
public class CleanWorkDirDialog extends Dialog {
protected IServer server;
protected IModule module;
protected int state;
protected String mode;
protected IStatus completionStatus;
/**
* Creates a dialog instance confirm deletion of the work directory for a
* module on a server, or the work directory for the entire server.
*
* @param parentShell the parent shell, or <code>null</code> to create a
* top-level shell
* @param server server on which to delete the work directory
* @param module module whose work directory is to be deleted, or <code>null</code> if
* if these server's entire work directory is to be deleted.
*/
public CleanWorkDirDialog(Shell parentShell, IServer server, IModule module) {
super(parentShell);
if (server == null)
throw new IllegalArgumentException();
this.server = server;
this.module = module;
}
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(Messages.confirmCleanWorkDirTitle);
}
protected Control createDialogArea(Composite parent) {
if (state < 0 || state == IServer.STATE_UNKNOWN)
captureServerState();
// create a composite with standard margins and spacing
Composite composite = (Composite)super.createDialogArea(parent);
// Since there are only label widgets on this page, set the help on the parent
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, ContextIds.SERVER_CLEAN_WORK_DIR);
Label label = new Label(composite, SWT.WRAP);
if (state == IServer.STATE_STARTING || state == IServer.STATE_STOPPING || state == IServer.STATE_UNKNOWN) {
label.setText(NLS.bind(Messages.cleanServerStateChanging, server.getName()));
}
else {
if (module != null)
label.setText(NLS.bind(Messages.cleanModuleWorkDir, module.getName(), server.getName()));
else
label.setText(NLS.bind(Messages.cleanServerWorkDir, server.getName()));
GridData data = new GridData();
data.widthHint = 300;
label.setLayoutData(data);
if (state == IServer.STATE_STARTED) {
label = new Label(composite, SWT.WRAP);
label.setText(Messages.cleanServerRunning);
data = new GridData();
data.widthHint = 300;
label.setLayoutData(data);
}
}
applyDialogFont(composite);
return composite;
}
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
if (state < 0 || state == IServer.STATE_UNKNOWN)
captureServerState();
// If server is transitioning, only allow Cancel
if (state == IServer.STATE_STARTING || state == IServer.STATE_STOPPING) {
Button button = getButton(IDialogConstants.OK_ID);
if (button != null)
button.setEnabled(false);
}
}
protected void okPressed() {
String jobName = NLS.bind(Messages.cleanServerTask,
module != null ? module.getName() : server.getName());
// Create job to perform the cleaning, including stopping and starting the server if necessary
CleanWorkDirJob job = new CleanWorkDirJob(jobName);
// Note: Since stop and start, if needed, will set scheduling rules in their jobs,
// don't set one here. Instead do the actual deletion in a child job too with the
// scheduling rule on that job, like stop and start.
job.schedule();
super.okPressed();
}
/*
* Job to clean the appropriate Tomcat work directory. It includes
* stopping and starting the server if the server is currently running.
* The stopping, deletion, and starting are all done with child jobs,
* each using the server scheduling rule. Thus, this job should
* not use this rule or it will block these child jobs.
*/
class CleanWorkDirJob extends Job {
/**
* @param name name for job
*/
public CleanWorkDirJob(String jobName) {
super(jobName);
}
/**
* @see Job#belongsTo(Object)
*/
public boolean belongsTo(Object family) {
return ServerUtil.SERVER_JOB_FAMILY.equals(family);
}
protected IStatus run(IProgressMonitor monitor) {
final Object mutex = new Object();
IWebModule webModule = null;
if (module != null) {
webModule = (IWebModule)module.loadAdapter(IWebModule.class, null);
if (webModule == null) {
return newErrorStatus(NLS.bind(Messages.errorCantIdentifyWebApp, module.getName()), null);
}
}
// If state has changed since dialog was open, abort
if (server.getServerState() != state) {
return newErrorStatus(
NLS.bind(Messages.errorCouldNotCleanStateChange, server.getName()), null);
}
IOperationListener listener = new IOperationListener() {
public void done(IStatus result) {
synchronized (mutex) {
completionStatus = result;
mutex.notifyAll();
}
}
};
boolean restart = false;
IStatus status = Status.OK_STATUS;
// If server isn't stopped, try to stop, clean, and restart
if (state != IServer.STATE_STOPPED) {
status = server.canStop();
if (!status.isOK()) {
return wrapErrorStatus(status,
NLS.bind(Messages.errorCouldNotCleanCantStop, server.getName()));
}
boolean done = false;
boolean force = false;
while (!done) {
// Stop the server and wait for completion
synchronized (mutex) {
server.stop(force, listener);
while (completionStatus == null) {
try {
mutex.wait();
} catch (InterruptedException e) {
// Ignore
}
}
}
// If forced, or there was an error (doesn't include timeout), or we are stopped, time to exit
if (force || !completionStatus.isOK() || server.getServerState() == IServer.STATE_STOPPED) {
done = true;
}
else {
force = TomcatUIPlugin.queryCleanTermination(server);
completionStatus = null;
}
}
if (!completionStatus.isOK()) {
// If stop job failed, assume error was displayed for that job
return Status.OK_STATUS;
}
if (server.getServerState() != IServer.STATE_STOPPED) {
return newErrorStatus(
NLS.bind(Messages.errorCouldNotCleanStopFailed, server.getName()), null);
}
restart = true;
completionStatus = null;
}
DeleteWorkDirJob deleteJob = new DeleteWorkDirJob(getName(), webModule, restart);
deleteJob.setRule(ServerUtil.getServerSchedulingRule(server));
deleteJob.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
synchronized (mutex) {
completionStatus = event.getResult();
mutex.notifyAll();
}
}
});
// Perform the work directory deletion job
synchronized (mutex) {
deleteJob.schedule();
while (completionStatus == null) {
try {
mutex.wait();
} catch (InterruptedException e) {
// Ignore
}
}
}
if (!completionStatus.isOK()) {
// If delete job failed, assume error was displayed for that job
return Status.OK_STATUS;
}
completionStatus = null;
if (restart) {
status = server.canStart(mode);
if (!status.isOK()) {
return wrapErrorStatus(status,
NLS.bind(Messages.errorCleanCantRestart, server.getName()));
}
// Restart the server and wait for completion
synchronized (mutex) {
server.start(mode, listener);
while (completionStatus == null) {
try {
mutex.wait();
} catch (InterruptedException e) {
// Ignore
}
}
}
if (!completionStatus.isOK()) {
// If start job failed, assume error was displayed for that job
return Status.OK_STATUS;
}
}
return status;
}
}
/*
* Job to actually delete the work directory. This is done
* in a separate job so it can be a "sibling" of potential
* stop and start jobs. This allows it to have a server
* scheduling rule.
*/
class DeleteWorkDirJob extends Job {
private IWebModule webModule;
private boolean restart;
/**
* @param name name for job
*/
public DeleteWorkDirJob(String jobName, IWebModule webModule, boolean restart) {
super(jobName);
this.webModule = webModule;
this.restart = restart;
}
/**
* @see Job#belongsTo(Object)
*/
public boolean belongsTo(Object family) {
return ServerUtil.SERVER_JOB_FAMILY.equals(family);
}
protected IStatus run(IProgressMonitor monitor) {
IStatus status = Status.OK_STATUS;
// If server isn't stopped, abort the attempt to delete the work directory
if (server.getServerState() != IServer.STATE_STOPPED) {
return newErrorStatus(
NLS.bind(Messages.errorCantDeleteServerNotStopped,
webModule != null ? module.getName() : server.getName()), null);
}
// Delete the work directory
TomcatServerBehaviour tsb = (TomcatServerBehaviour)server.loadAdapter(
TomcatServerBehaviour.class, monitor);
try {
if (webModule != null) {
ITomcatWebModule tcWebModule = new WebModule(webModule.getContextRoot(), "", "", true);
status = tsb.cleanContextWorkDir(tcWebModule, null);
}
else {
status = tsb.cleanServerWorkDir(null);
}
} catch (CoreException ce) {
status = ce.getStatus();
}
if (!status.isOK()) {
String cleanName = module != null ? module.getName() : server.getName();
return wrapErrorStatus(status,
restart ?
NLS.bind(Messages.errorErrorDuringCleanWasRunning,
cleanName , server.getName()) :
NLS.bind(Messages.errorErrorDuringClean, cleanName));
}
return status;
}
}
private void captureServerState() {
state = server.getServerState();
if (state != IServer.STATE_STOPPED) {
mode = server.getMode();
}
}
protected IStatus newErrorStatus(String message, Throwable throwable) {
return new Status(IStatus.ERROR, TomcatUIPlugin.PLUGIN_ID, 0,
message, throwable);
}
protected IStatus wrapErrorStatus(IStatus status, String message) {
MultiStatus ms = new MultiStatus(TomcatUIPlugin.PLUGIN_ID, 0, message, null);
ms.add(status);
return ms;
}
}