/******************************************************************************* * 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; } }