[211207] PublishUtil ignore publish support
diff --git a/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/PublishUtil.java b/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/PublishUtil.java
index 640e2b5..794a15b 100644
--- a/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/PublishUtil.java
+++ b/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/PublishUtil.java
@@ -27,12 +27,10 @@
  * It is not intended to be subclassed or instantiated.
  * </p>
  * <p>
- * <b>Note:</b> This class/interface is part of an interim API that is still under development and expected to
- * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
- * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
- * (repeatedly) as the API evolves.
+ * <b>Note:</b> Adopters should use the equivalent class in
+ * org.eclipse.wst.server.core.util instead. This class will eventually
+ * be deprecated.
  * </p>
- * @plannedfor 3.0
  */
 public final class PublishUtil {
 	// size of the buffer
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModuleFile.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModuleFile.java
index e0d575c..cb13d93 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModuleFile.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModuleFile.java
@@ -30,7 +30,7 @@
 		super(file, name, path);
 	}
 
-	/**
+	/*
 	 * @deprecated use another constructor
 	 */
 	public ModuleFile(IFile file, String name, IPath path, long stamp) {
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 3afe13f..29e65ec 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
@@ -207,11 +207,11 @@
 			return Status.OK_STATUS;
 		}
 	}
-	
-	private static final Comparator PUBLISH_OPERATION_COMPARTOR = new Comparator() {
-      public int compare(Object leftOp, Object rightOp) {
-          PublishOperation left = (PublishOperation) leftOp;
-          PublishOperation right = (PublishOperation) rightOp;
+
+	private static final Comparator<PublishOperation> PUBLISH_OPERATION_COMPARTOR = new Comparator<PublishOperation>() {
+      public int compare(PublishOperation leftOp, PublishOperation rightOp) {
+          PublishOperation left = leftOp;
+          PublishOperation right = rightOp;
           if (left.getOrder() > right.getOrder())
               return 1;
           if (left.getOrder() < right.getOrder())
@@ -233,8 +233,8 @@
 		this.serverType = serverType;
 		map.put("server-type-id", serverType.getId());
 		map.put(PROP_HOSTNAME, "localhost");
-		map.put(PROP_START_TIMEOUT, ((ServerType)serverType).getStartTimeout());
-		map.put(PROP_STOP_TIMEOUT, ((ServerType)serverType).getStopTimeout());
+		map.put(PROP_START_TIMEOUT, new Integer(((ServerType)serverType).getStartTimeout()));
+		map.put(PROP_STOP_TIMEOUT, new Integer(((ServerType)serverType).getStopTimeout()));
 		if (runtime != null && runtime.getRuntimeType() != null) {
 			String name = runtime.getRuntimeType().getName();
 			map.put(PROP_NAME, name);
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishHelper.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishHelper.java
index da7f944..91a0dfa 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishHelper.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishHelper.java
@@ -176,6 +176,20 @@
 	 * @return a possibly-empty array of error and warning status 
 	 */
 	public IStatus[] publishSmart(IModuleResource[] resources, IPath path, IProgressMonitor monitor) {
+		return publishSmart(resources, path, null, monitor);
+	}
+
+	/**
+	 * Smart copy the given module resources to the given path.
+	 * 
+	 * @param resources an array of module resources
+	 * @param path an external path to copy to
+	 * @param ignore an array of paths relative to path to ignore, i.e. not delete or copy over
+	 * @param monitor a progress monitor, or <code>null</code> if progress
+	 *    reporting and cancellation are not desired
+	 * @return a possibly-empty array of error and warning status 
+	 */
+	public IStatus[] publishSmart(IModuleResource[] resources, IPath path, IPath[] ignore, IProgressMonitor monitor) {
 		if (resources == null)
 			return EMPTY_STATUS;
 		
@@ -187,6 +201,14 @@
 		String[] fromFileNames = new String[fromSize];
 		for (int i = 0; i < fromSize; i++)
 			fromFileNames[i] = resources[i].getName();
+		List<String> ignoreFileNames = new ArrayList<String>();
+		if (ignore != null) {
+			for (int i = 0; i < ignore.length; i++) {
+				if (ignore[i].segmentCount() == 1) {
+					ignoreFileNames.add(ignore[i].toOSString());
+				}
+			}
+		}
 		
 		//	cache files and file names for performance
 		File[] toFiles = null;
@@ -206,18 +228,30 @@
 					boolean isDir = toFiles[i].isDirectory();
 					boolean found = false;
 					for (int j = 0; j < fromSize; j++) {
-						if (toFileNames[i].equals(fromFileNames[j]) && isDir == resources[j] instanceof IModuleFolder)
+						if (toFileNames[i].equals(fromFileNames[j]) && isDir == resources[j] instanceof IModuleFolder) {
 							found = true;
+							break;
+						}
 					}
 					
 					// delete file if it can't be found or isn't the correct type
 					if (!found) {
-						if (isDir) {
-							IStatus[] stat = deleteDirectory(toFiles[i], null);
-							addArrayToList(status, stat);
-						} else {
-							if (!toFiles[i].delete())
-								status.add(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorDeleting, toFiles[i].getAbsolutePath()), null));
+						boolean delete = true;
+						// if should be preserved, don't delete and don't try to copy
+						for (String preserveFileName : ignoreFileNames) {
+							if (toFileNames[i].equals(preserveFileName)) {
+								delete = false;
+								break;
+							}
+						}
+						if (delete) {
+							if (isDir) {
+								IStatus[] stat = deleteDirectory(toFiles[i], null);
+								addArrayToList(status, stat);
+							} else {
+								if (!toFiles[i].delete())
+									status.add(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorDeleting, toFiles[i].getAbsolutePath()), null));
+							}
 						}
 						toFiles[i] = null;
 						toFileNames[i] = null;
@@ -289,8 +323,10 @@
 				}
 				
 				for (int j = 0; j < toSize; j++) {
-					if (name.equals(toFileNames[j]) && mod == toFileMod[j])
+					if (name.equals(toFileNames[j]) && mod == toFileMod[j]) {
 						copy = false;
+						break;
+					}
 				}
 				
 				if (copy) {
@@ -304,8 +340,22 @@
 			} else { //if (currentIsDir) {
 				IModuleFolder folder = (IModuleFolder) current;
 				IModuleResource[] children = folder.members();
+
+				// build array of ignored Paths that apply to this folder
+				IPath[] ignoreChildren = null;
+				if (ignore != null) {
+					List<IPath> ignoreChildPaths = new ArrayList<IPath>();
+					for (int j = 0; j < ignore.length; j++) {
+						IPath preservePath = ignore[j];
+						if (preservePath.segment(0).equals(name)) {
+							ignoreChildPaths.add(preservePath.removeFirstSegments(1));
+						}
+					}
+					if (ignoreChildPaths.size() > 0)
+						ignoreChildren = ignoreChildPaths.toArray(new Path[ignoreChildPaths.size()]);
+				}
 				monitor.subTask(NLS.bind(Messages.copyingTask, new String[] {name, name}));
-				IStatus[] stat = publishSmart(children, path.append(name), ProgressUtil.getSubMonitorFor(monitor, dw));
+				IStatus[] stat = publishSmart(children, path.append(name), ignoreChildren, ProgressUtil.getSubMonitorFor(monitor, dw));
 				addArrayToList(status, stat);
 			}
 		}
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishUtil.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishUtil.java
index c9f44c3..66e0247 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishUtil.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/util/PublishUtil.java
@@ -59,6 +59,20 @@
 	}
 
 	/**
+	 * Smart copy the given module resources to the given path.
+	 * 
+	 * @param resources an array of module resources
+	 * @param path an external path to copy to
+	 * @param ignore an array of paths relative to path to ignore, i.e. not delete or copy over
+	 * @param monitor a progress monitor, or <code>null</code> if progress
+	 *    reporting and cancellation are not desired
+	 * @return a possibly-empty array of error and warning status 
+	 */
+	public static IStatus[] publishSmart(IModuleResource[] resources, IPath path, IPath[] ignore, IProgressMonitor monitor) {
+		return publishHelper.publishSmart(resources, path, ignore, monitor);
+	}
+
+	/**
 	 * Handle a delta publish.
 	 * 
 	 * @param delta a module resource delta
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/ServerToolTip.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/ServerToolTip.java
index 7f38467..a2c91af 100644
--- a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/ServerToolTip.java
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/ServerToolTip.java
@@ -53,9 +53,9 @@
  * 
  */
 public class ServerToolTip extends ToolTip {	
-	protected Hashtable<String,ArrayList> toolTipProviders = new Hashtable<String,ArrayList>();	
+	protected Hashtable<String,ArrayList<IServerToolTip>> toolTipProviders = new Hashtable<String,ArrayList<IServerToolTip>>();	
 	protected static Shell CURRENT_TOOLTIP;
-	private Label hintLabel;
+	protected Label hintLabel;
 	protected Server server;
 	protected Tree tree;
 	protected int x;