[390105] Publish before start servers synchronization problem
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 19d6ec0..13fdda4 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
@@ -1898,7 +1898,7 @@
 		job.schedule();
 	}
 
-	protected IStatus publishBeforeStart(IProgressMonitor monitor, boolean synchronous){
+	protected IStatus publishBeforeStart(IProgressMonitor monitor, final StartJob startJob, final boolean synchronous){
 
 		// check if we need to publish
 		byte pub = StartJob.PUBLISH_NONE;
@@ -1917,22 +1917,53 @@
 			pubJob.addJobChangeListener(new JobChangeAdapter(){
 				public void done(IJobChangeEvent event) {
 					IStatus status = event.getResult();
-					if (status != null && status.getSeverity() == IStatus.ERROR)
-						pubStatus[0] = status; 
+					if (status != null && status.getSeverity() == IStatus.ERROR) {
+						pubStatus[0] = status;
+						if (Trace.INFO) {
+							Trace.trace(Trace.STRING_INFO,
+									"Skipping server start job schedule since the server publish failed on a publish before start server.");
+						}
+					} else {
+						if (Trace.INFO) {
+							Trace.trace(Trace.STRING_INFO,
+									"Scheduling server start job after successful publish.");
+						}
+						// Schedule the server start job since the publish operation is completed successfully.
+						startJob.schedule();
+						
+						try {
+							if (synchronous)
+								startJob.join();
+						} catch (InterruptedException e) {
+							if (Trace.WARNING) {
+								Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+							}
+						}
+					}
 				}
 				
 			});
-			
 			pubJob.schedule();
 			
-			try{
+			try {
 				if (synchronous)
 					pubJob.join();
-					
-			}
-			catch (InterruptedException ie){
+			} catch (InterruptedException ie) {
 				return Status.CANCEL_STATUS;
 			}
+		} else {
+			// Schedule the server start since a publish is not needed so 
+			// Schedule the server start job since the publish operation is completed successfully.
+			startJob.schedule();
+			
+			try {
+				if (synchronous)
+					startJob.join();
+			} catch (InterruptedException e) {
+				if (Trace.WARNING) {
+					Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+				}
+			}
 		}
 		return pubStatus[0];
 	}
@@ -1996,20 +2027,10 @@
 		// make sure that the delegate is loaded and the server state is correct
 		loadAdapter(ServerBehaviourDelegate.class, null);
 		
-		boolean synchronous = ((ServerType)getServerType()).synchronousStart();
-		IStatus status = publishBeforeStart(monitor,synchronous);
-		
-		if (status != null && status.getSeverity() == IStatus.ERROR){
-			if (Trace.FINEST) {
-				Trace.trace(Trace.STRING_FINEST, "Failed publish job during start routine");
-			}
-			return;
-		}
-		
 		StartJob startJob = new StartJob(mode2);
 		// 287442 - only do publish after start if the server start is successful.
 		final IProgressMonitor monitor2 = monitor; 
-		final boolean synchronous2 = synchronous;
+		final boolean synchronous = ((ServerType)getServerType()).synchronousStart();
 		startJob.addJobChangeListener(new JobChangeAdapter() {
 			public void done(IJobChangeEvent event) {
 				IStatus resultStatus = event.getResult();
@@ -2019,17 +2040,29 @@
 								"Skipping auto publish after server start since the server start failed.");
 					}
 				} else {
-					publishAfterStart(monitor2,synchronous2,null);
+					publishAfterStart(monitor2,synchronous,null);
 				}
 			}
 		});
-		startJob.schedule();
-		try {
-			if(synchronous)
-				startJob.join();
-		} catch (InterruptedException e) {
-			if (Trace.WARNING) {
-				Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+		// Forces synchronous start since this method is supposed to wait until the publish operation is completed.
+		IStatus status = publishBeforeStart(monitor, startJob, true);
+		
+		if (status != null && status.getSeverity() == IStatus.ERROR){
+			if (Trace.FINEST) {
+				Trace.trace(Trace.STRING_FINEST, "Failed publish job during start routine");
+			}
+			return;
+		}
+		
+		if (((ServerType)getServerType()).startBeforePublish()) {
+			startJob.schedule();
+			try {
+				if(synchronous)
+					startJob.join();
+			} catch (InterruptedException e) {
+				if (Trace.WARNING) {
+					Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+				}
 			}
 		}
 	}
@@ -2047,18 +2080,6 @@
 		// make sure that the delegate is loaded and the server state is correct
 		loadAdapter(ServerBehaviourDelegate.class, null);
 		
-		boolean synchronous = ((ServerType)getServerType()).synchronousStart();
-		IStatus status = publishBeforeStart(null,synchronous);
-		
-		if (status != null && status.getSeverity() == IStatus.ERROR){
-			if (Trace.FINEST) {
-				Trace.trace(Trace.STRING_FINEST, "Failed publish job during start routine");
-			}
-			if (opListener != null)
-				opListener.done(Status.OK_STATUS);
-			return;
-		}
-
 		// check the publish flag (again) to determine when to call opListener.done 
 		byte pub = StartJob.PUBLISH_NONE;
 		if (ServerCore.isAutoPublishing() && shouldPublish()) {
@@ -2080,8 +2101,22 @@
 				}
 			});
 		}
+		
+		final boolean synchronous = ((ServerType)getServerType()).synchronousStart();
+		// For publish before start servers, the start job will only be kicked off if the publishing
+		// operation is completed successfully.
+		IStatus status = publishBeforeStart(null, startJob, synchronous);
+		
+		if (status != null && status.getSeverity() == IStatus.ERROR){
+			if (Trace.FINEST) {
+				Trace.trace(Trace.STRING_FINEST, "Failed publish job during start routine");
+			}
+			if (opListener != null)
+				opListener.done(Status.OK_STATUS);
+			return;
+		}
+
 		// 287442 - only do publish after start if the server start is successful.
-		final boolean synchronous2 = synchronous;
 		if (pub == StartJob.PUBLISH_AFTER) {
 			startJob.addJobChangeListener(new JobChangeAdapter() {
 				public void done(IJobChangeEvent event) {
@@ -2096,19 +2131,19 @@
 							opListener.done(Status.OK_STATUS);
 					}
 					else {
-						publishAfterStart(null,synchronous2,opListener);
+						publishAfterStart(null,synchronous,opListener);
 					}
 				}
 			});
-		}
-		startJob.schedule();
-		
-		try {
-			if(synchronous)
-				startJob.join();
-		} catch (InterruptedException e) {
-			if (Trace.WARNING) {
-				Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+			startJob.schedule();
+			
+			try {
+				if(synchronous)
+					startJob.join();
+			} catch (InterruptedException e) {
+				if (Trace.WARNING) {
+					Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+				}
 			}
 		}
 	}
@@ -2120,15 +2155,6 @@
 		// make sure that the delegate is loaded and the server state is correct
 		loadAdapter(ServerBehaviourDelegate.class, monitor);
 		
-		IStatus status = publishBeforeStart(monitor,true);
-		
-		if (status != null && status.getSeverity() == IStatus.ERROR){
-			if (Trace.FINEST) {
-				Trace.trace(Trace.STRING_FINEST, "Failed publish job during start routine");
-			}
-			return;
-		}
-		
 		StartJob startJob = new StartJob(mode2);
 		// 287442 - only do publish after start if the server start is successful.
 		final IProgressMonitor monitor2 = monitor; 
@@ -2145,13 +2171,25 @@
 				}
 			}
 		});
-		startJob.schedule();
 		
-		try {
-			startJob.join();
-		} catch (InterruptedException e) {
-			if (Trace.WARNING) {
-				Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+		IStatus status = publishBeforeStart(monitor, startJob, true);
+		
+		if (status != null && status.getSeverity() == IStatus.ERROR){
+			if (Trace.FINEST) {
+				Trace.trace(Trace.STRING_FINEST, "Failed publish job during start routine");
+			}
+			return;
+		}
+		
+		if (((ServerType)getServerType()).startBeforePublish()) {
+			startJob.schedule();
+			
+			try {
+				startJob.join();
+			} catch (InterruptedException e) {
+				if (Trace.WARNING) {
+					Trace.trace(Trace.STRING_WARNING, "Error waiting for job", e);
+				}
 			}
 		}
 	}
@@ -3154,6 +3192,7 @@
 			Trace.trace(Trace.STRING_FINEST, "Restarting server: " + getName());
 		}
 		
+		ISchedulingRule curRule = null;
 		try {
 			try {
 				// synchronous restart
@@ -3170,24 +3209,21 @@
 			}
 			// if restart is not implemented by the server adopter
 			// lets provide a default implementation
+			// Ending the current rule setup by the RestartJob to prevent deadlock since the StopJob triggered
+			// by the stop(false) also setup the Server as the scheduling rule.
+			curRule = Job.getJobManager().currentRule();
+			Job.getJobManager().endRule(curRule);
 			stop(false);
-			ISchedulingRule curRule = null;
-			try {
-				if (((ServerType)getServerType()).synchronousStart()) {
-					curRule = Job.getJobManager().currentRule();
-					Job.getJobManager().endRule(curRule);
-				}
-				start(launchMode, monitor);
-			} finally {
-				if (curRule != null) {
-					Job.getJobManager().beginRule(curRule, monitor);
-				}
-			}
+			start(launchMode, monitor);
 		} catch (Exception e) {
 			if (Trace.SEVERE) {
 				Trace.trace(Trace.STRING_SEVERE, "Error restarting server", e);
 			}
 			return new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorStartFailed, getName()), e);
+		} finally {
+			if (curRule != null) {
+				Job.getJobManager().beginRule(curRule, monitor);
+			}
 		}
 		return Status.OK_STATUS;
 	}