[169570] Publish modules
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/IServer.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/IServer.java
index 7783fbe..5b777be 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/IServer.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/IServer.java
@@ -307,9 +307,9 @@
 	 * and the risk of UI deadlock is high. 
 	 * </p>
 	 * 
-	 * @param kind the kind of publish being requested. Valid values are
+	 * @param kind the kind of publish being requested. Valid values are:
 	 *    <ul>
-	 *    <li><code>PUBLSIH_FULL</code>- indicates a full publish.</li>
+	 *    <li><code>PUBLISH_FULL</code>- indicates a full publish.</li>
 	 *    <li><code>PUBLISH_INCREMENTAL</code>- indicates a incremental publish.
 	 *    <li><code>PUBLISH_CLEAN</code>- indicates a clean request. Clean throws
 	 *      out all state and cleans up the module on the server before doing a
@@ -318,10 +318,42 @@
 	 * @param monitor a progress monitor, or <code>null</code> if progress
 	 *    reporting and cancellation are not desired
 	 * @return status indicating what (if anything) went wrong
+	 * @see #publish(int, IModule[], org.eclipse.wst.server.core.IServer.IOperationListener)
 	 */
 	public IStatus publish(int kind, IProgressMonitor monitor);
 
 	/**
+	 * Publish one or more modules to the server.
+	 * <p>
+	 * The operation listener can be used to add a listener for notification
+	 * of the publish result. The listener will be called with a
+	 * single successful status (severity OK) when the server has
+	 * finished publishing, or a single failure (severity ERROR) if
+	 * there was an error publishing to the server.
+	 * </p><p>
+	 * This method should not be called from the UI thread. Publishing is long-
+	 * running and may trigger resource change events or builds. Although this
+	 * framework is safe, there is no guarantee that other bundles are UI-safe
+	 * and the risk of UI deadlock is high. 
+	 * </p>
+	 * 
+	 * @param kind the kind of publish being requested. Valid values are:
+	 *    <ul>
+	 *    <li><code>PUBLISH_FULL</code>- indicates a full publish.</li>
+	 *    <li><code>PUBLISH_INCREMENTAL</code>- indicates a incremental publish.
+	 *    <li><code>PUBLISH_CLEAN</code>- indicates a clean request. Clean throws
+	 *      out all state and cleans up the module on the server before doing a
+	 *      full publish.
+	 *    </ul>
+	 * @param modules an array of modules, or <code>null</code> to publish all
+	 *    modules
+	 *  @param listener an operation listener to receive notification when this
+	 *    operation is done, or <code>null</code> if notification is not
+	 *    required
+	 */
+	public void publish(int kind, IModule[] modules, IOperationListener listener);
+
+	/**
 	 * Returns whether this server is in a state that it can
 	 * be started in the given mode.
 	 *
@@ -342,7 +374,7 @@
 	 * <p>
 	 * If the caller wants to listen for failure or success of the
 	 * server starting, it can add a server listener or use the
-	 * version of this method that takes a status listener as a
+	 * version of this method that takes an operation listener as a
 	 * parameter.
 	 * </p>
 	 *
@@ -352,9 +384,10 @@
 	 * @param monitor a progress monitor, or <code>null</code> if progress
 	 *    reporting and cancellation are not desired
 	 * @exception CoreException if an error occurs while trying to start the server
+	 * @see #start(String, org.eclipse.wst.server.core.IServer.IOperationListener)
 	 */
 	public void start(String launchMode, IProgressMonitor monitor) throws CoreException;
-	
+
 	/**
 	 * Asynchronously starts this server in the given launch mode.
 	 * <p>
@@ -379,26 +412,6 @@
 	public void start(String launchMode, IOperationListener listener);
 
 	/**
-	 * Starts this server in the given launch mode and waits until the server
-	 * has finished starting.
-	 * <p>
-	 * This convenience method uses {@link #start(String, IProgressMonitor)}
-	 * to start the server, and an internal thread and listener to detect
-	 * when the server has finished starting.
-	 * </p>
-	 *
-	 * @param launchMode a mode in which a server can be launched,
-	 *    one of the mode constants defined by
-	 *    {@link org.eclipse.debug.core.ILaunchManager}
-	 * @param monitor a progress monitor, or <code>null</code> if progress
-	 *    reporting and cancellation are not desired
-	 * @deprecated this method is deprecated. use start(String,
-	 *    IProgressMonitor, IOperationListener) instead
-	 * @exception CoreException if an error occurs while trying to start the server
-	 */
-	public void synchronousStart(String launchMode, IProgressMonitor monitor) throws CoreException;
-
-	/**
 	 * Returns whether this server is in a state that it can
 	 * be restarted in the given mode. Note that only servers
 	 * that are currently running can be restarted.
@@ -445,7 +458,7 @@
 	 * <p>
 	 * If the caller wants to listen for failure or success of the
 	 * server restarting, it can add a server listener or use the
-	 * version of this method that takes a status listener as a
+	 * version of this method that takes an operation listener as a
 	 * parameter.
 	 * </p>
 	 *
@@ -454,6 +467,7 @@
 	 *    {@link org.eclipse.debug.core.ILaunchManager}
 	 * @param monitor a progress monitor, or <code>null</code> if progress
 	 *    reporting and cancellation are not desired
+	 * @see #restart(String, org.eclipse.wst.server.core.IServer.IOperationListener)
 	 */
 	public void restart(String launchMode, IProgressMonitor monitor);
 
@@ -480,28 +494,6 @@
 	public void restart(String launchMode, IOperationListener listener);
 
 	/**
-	 * Synchronously restarts this server. This operation does
-	 * nothing if this server cannot be stopped ({@link #canRestart(String)}
-	 * returns <code>false</code>.
-	 * <p>
-	 * [issue: There is no way to communicate failure to the
-	 * client. Given that this operation can go awry, there probably
-	 * should be a mechanism that allows failing asynch operations
-	 * to be diagnosed.]
-	 * </p>
-	 *
-	 * @param launchMode a mode in which a server can be launched,
-	 *    one of the mode constants defined by
-	 *    {@link org.eclipse.debug.core.ILaunchManager}
-	 * @param monitor a progress monitor, or <code>null</code> if progress
-	 *    reporting and cancellation are not desired
-	 * @throws CoreException if there was an error
-	 * @deprecated this method is deprecated. use restart(String,
-	 *    IProgressMonitor, IOperationListener) instead
-	 */
-	public void synchronousRestart(String launchMode, IProgressMonitor monitor) throws CoreException;
-
-	/**
 	 * Returns whether this server is in a state that it can
 	 * be stopped.
 	 * Servers can be stopped if they are not already stopped and if
@@ -524,12 +516,13 @@
 	 * <p>
 	 * If the caller wants to listen for success or failure of the
 	 * server stopping, it can add a server listener or use the
-	 * version of this method that takes a status listener as a
+	 * version of this method that takes an operation listener as a
 	 * parameter.
 	 * </p>
 	 * 
 	 * @param force <code>true</code> to kill the server, or <code>false</code>
 	 *    to stop normally
+	 * @see #start(String, org.eclipse.wst.server.core.IServer.IOperationListener)
 	 */
 	public void stop(boolean force);
 
@@ -559,21 +552,6 @@
 	public void stop(boolean force, IOperationListener listener);
 
 	/**
-	 * Stops this server and waits until the server has completely stopped.
-	 * <p>
-	 * This convenience method uses {@link #stop(boolean)}
-	 * to stop the server, and an internal thread and listener to detect
-	 * when the server has complied.
-	 * </p>
-	 * 
-	 * @param force <code>true</code> to kill the server, or <code>false</code>
-	 *    to stop normally
-	 * @deprecated this method is deprecated. use stop(boolean,
-	 *    IOperationListener) instead
-	 */
-	public void synchronousStop(boolean force);
-
-	/**
 	 * Returns the current state of the given module on this server.
 	 * Returns <code>STATE_UNKNOWN</code> if the module
 	 * is not among the ones associated with this server.
@@ -664,14 +642,6 @@
 	 * an exception will be thrown.
 	 * </p>
 	 * <p>
-	 * [issue: Since this method is asynchronous, is there
-	 * any need for the progress monitor?]
-	 * </p>
-	 * <p>
-	 * [issue: IServer.synchronousModuleRestart throws CoreException
-	 * if anything goes wrong.]
-	 * </p>
-	 * <p>
 	 * [issue: If the module was just published to the server
 	 * and had never been started, would is be ok to "start"
 	 * the module using this method?]
@@ -710,4 +680,56 @@
 	 * @since 3.0
 	 */
 	public ILaunch getLaunch();
+
+	/**
+	 * Starts this server in the given launch mode and waits until the server
+	 * has finished starting.
+	 * <p>
+	 * This convenience method uses {@link #start(String, IProgressMonitor)}
+	 * to start the server, and an internal thread and listener to detect
+	 * when the server has finished starting.
+	 * </p>
+	 *
+	 * @param launchMode a mode in which a server can be launched,
+	 *    one of the mode constants defined by
+	 *    {@link org.eclipse.debug.core.ILaunchManager}
+	 * @param monitor a progress monitor, or <code>null</code> if progress
+	 *    reporting and cancellation are not desired
+	 * @deprecated use {@link #start(String, org.eclipse.wst.server.core.IServer.IOperationListener)}
+	 *    instead
+	 * @exception CoreException if an error occurs while trying to start the server
+	 */
+	public void synchronousStart(String launchMode, IProgressMonitor monitor) throws CoreException;
+
+	/**
+	 * Stops this server and waits until the server has completely stopped.
+	 * <p>
+	 * This convenience method uses {@link #stop(boolean)}
+	 * to stop the server, and an internal thread and listener to detect
+	 * when the server has complied.
+	 * </p>
+	 * 
+	 * @param force <code>true</code> to kill the server, or <code>false</code>
+	 *    to stop normally
+	 * @deprecated use {@link #stop(boolean, org.eclipse.wst.server.core.IServer.IOperationListener)}
+	 *    instead
+	 */
+	public void synchronousStop(boolean force);
+
+	/**
+	 * Synchronously restarts this server. This operation does
+	 * nothing if this server cannot be stopped ({@link #canRestart(String)}
+	 * returns <code>false</code>.
+	 * <p>
+	 *
+	 * @param launchMode a mode in which a server can be launched,
+	 *    one of the mode constants defined by
+	 *    {@link org.eclipse.debug.core.ILaunchManager}
+	 * @param monitor a progress monitor, or <code>null</code> if progress
+	 *    reporting and cancellation are not desired
+	 * @throws CoreException if there was an error
+	 * @deprecated use {@link #restart(String, org.eclipse.wst.server.core.IServer.IOperationListener)} 
+	 *    instead
+	 */
+	public void synchronousRestart(String launchMode, IProgressMonitor monitor) throws CoreException;
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java
index 8023f1d..feb89ff 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java
@@ -312,7 +312,7 @@
 		if (behaviourDelegate != null || serverType == null)
 			return behaviourDelegate;
 		
-		synchronized (this) {
+		synchronized (moduleState) {
 			if (behaviourDelegate == null) {
 				try {
 					long time = System.currentTimeMillis();
@@ -859,7 +859,7 @@
 	 * Publish to the server using the progress monitor. The result of the
 	 * publish operation is returned as an IStatus.
 	 */
-	public IStatus publish(final int kind, IProgressMonitor monitor) {
+	public IStatus publish(int kind, IProgressMonitor monitor) {
 		if (getServerType() == null)
 			return new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, 0, Messages.errorMissingAdapter, null);
 
@@ -887,6 +887,43 @@
 		return status;
 	}
 
+	/*
+	 * Publish the given modules to the server.
+	 * TODO: Implementation!
+	 */
+	public void publish(int kind, IModule[] modules2, IOperationListener listener) {
+		if (getServerType() == null) {
+			listener.done(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, 0, Messages.errorMissingAdapter, null));
+			return;
+		}
+		
+		// check what is out of sync and publish
+		if (getServerType().hasServerConfiguration() && configuration == null) {
+			listener.done(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, 0, Messages.errorNoConfiguration, null));
+			return;
+		}
+		
+		// make sure that the delegate is loaded and the server state is correct
+		loadAdapter(ServerBehaviourDelegate.class, null);
+		
+		if (((ServerType)getServerType()).startBeforePublish() && (getServerState() == IServer.STATE_STOPPED)) {
+			try {
+				synchronousStart(ILaunchManager.RUN_MODE, new NullProgressMonitor());
+			} catch (CoreException ce) {
+				Trace.trace(Trace.SEVERE, "Error starting server", ce);
+				listener.done(ce.getStatus());
+				return;
+			}
+		}
+		
+		long time = System.currentTimeMillis();
+		firePublishStarted();
+		IStatus status = doPublish(kind, new NullProgressMonitor());
+		firePublishFinished(status);
+		Trace.trace(Trace.PERFORMANCE, "Server.publish(): <" + (System.currentTimeMillis() - time) + "> " + getServerType().getId());
+		listener.done(status);
+	}
+
 	protected IStatus doPublish(int kind, IProgressMonitor monitor) {
 		Trace.trace(Trace.FINEST, "-->-- Publishing to server: " + toString() + " -->--");
 		
@@ -919,7 +956,7 @@
 	}
 
 	/**
-	 * Returns the publish tasks that have been targetted to this server.
+	 * Returns the publish tasks that have been targeted to this server.
 	 * These tasks should be run during publishing and will be initialized
 	 * with a task model.
 	 *