[137628] Treat a context-root of "/" as an alias for "".  Also check for multiple contexts with the same path.
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.java
index 1cd305b..be010f0 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.java
@@ -58,6 +58,7 @@
 	public static String checkingContextTask;
 	public static String serverPostProcessingComplete;
 	public static String errorPublishConfiguration;
+	public static String errorPublishServer;
 	public static String cleanupServerTask;
 	public static String detectingRemovedProjects;
 	public static String deletingContextFilesTask;
@@ -90,6 +91,9 @@
 	public static String errorPublishURLConvert;
 	public static String errorPublishCantDeleteLoaderJar;
 	public static String errorPublishCatalinaProps;
+	public static String errorPublishPathDup;
+	public static String errorPublishPathConflict;
+	public static String errorPublishPathMissing;
 
 	public static String configurationEditorActionModifyPort;
 	public static String configurationEditorActionModifyMimeMapping;
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.properties b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.properties
index 5454c7a..2addb48 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.properties
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Messages.properties
@@ -79,6 +79,7 @@
 errorCouldNotLoadConfiguration=Could not load the Tomcat server configuration at {0}. The configuration may be corrupt or incomplete.
 errorCouldNotSaveConfiguration=Could not save the Tomcat server configuration: {0}.
 errorPublishConfiguration=Could not publish server configuration: {0}.
+errorPublishServer=Could not publish server configuration for {0}.
 errorCouldNotDeleteContextFile=Could not delete obsolete context file: {0}
 errorCleanupServer=Could not clean server of obsolete files: {0}
 errorWebModulesOnly=Tomcat only supports running J2EE Web modules.
@@ -107,6 +108,9 @@
 errorPublishURLConvert=Exception occurred converting URL {0}: {1}.
 errorPublishCantDeleteLoaderJar=Unable to delete the custom loader jar {0} from Tomcat server.
 errorPublishCatalinaProps=Exception occurred modifying catalina.properties: {0}.
+errorPublishPathDup=Multiple Contexts have a path of "{0}".
+errorPublishPathConflict=Context with path "{0}" conflicts with another Context with path "{1}".
+errorPublishPathMissing=A Context was found with no path.
 
 warningJRE=Tomcat requires a Java SDK in order to compile JSP files. Ensure that the JRE preference settings point to an SDK install location.
 warningCantReadConfig=Cannot read the Tomcat configuration.
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Configuration.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Configuration.java
index 6d1e958..2754316 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Configuration.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Configuration.java
@@ -12,9 +12,11 @@
 
 import java.io.*;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.eclipse.core.resources.IFile;
@@ -499,11 +501,59 @@
 			boolean addRootWebapp = server2.isTestEnvironment();
 			
 			// If not deploying to "webapps", context docBase attributes need updating
-			if (!"webapps".equals(server2.getDeployDirectory())) {
-				Context [] contexts = config.serverInstance.getContexts();
-				if (contexts != null) {
-					for (int i = 0; i < contexts.length; i++) {
-						Context context = contexts[i];
+			boolean deployingToWebapps = "webapps".equals(server2.getDeployDirectory());
+			
+			Map pathMap = new HashMap();
+			
+			MultiStatus ms = new MultiStatus(TomcatPlugin.PLUGIN_ID, 0, 
+					NLS.bind(Messages.errorPublishServer, server2.getServer().getName()), null);
+			Context [] contexts = config.serverInstance.getContexts();
+			if (contexts != null) {
+				for (int i = 0; i < contexts.length; i++) {
+					Context context = contexts[i];
+
+					// Normalize path and check for duplicates
+					String path = context.getPath();
+					if (path != null) {
+						// Save a copy of original in case it's "/"
+						String origPath = path;
+						// Normalize "/" to ""
+						if ("/".equals(path)) {
+							if (Trace.isTraceEnabled())
+								Trace.trace(Trace.FINER, "Context path is being changed from \"/\" to \"\".");
+							path = "";
+							context.setPath(path);
+							config.isServerDirty = true;
+						}
+
+						// Context paths that are the same or differ only in case are not allowed
+						String lcPath = path.toLowerCase();
+						if (!pathMap.containsKey(lcPath)) {
+							pathMap.put(lcPath, origPath);
+						}
+						else {
+							String otherPath = (String)pathMap.get(lcPath);
+							IStatus s = new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID,
+									origPath.equals(otherPath) ? NLS.bind(Messages.errorPublishPathDup, origPath) 
+											: NLS.bind(Messages.errorPublishPathConflict, origPath, otherPath));
+							ms.add(s);
+						}
+					}
+					else {
+						IStatus s = new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID,
+								Messages.errorPublishPathMissing);
+						ms.add(s);
+					}
+
+					// If default webapp has not been found, check this one
+					// TODO Need to add a root context if deploying to webapps but with auto-deploy off
+					if (addRootWebapp && "".equals(context.getPath())) {
+						// A default webapp is being deployed, don't add one
+						addRootWebapp = false;
+					}
+
+					// If not deploying to "webapps", convert to absolute path under deploy dir
+					if (!deployingToWebapps) {
 						String source = context.getSource();
 						if (source != null && source.length() > 0 )	{
 							String name = context.getDocBase();
@@ -514,15 +564,12 @@
 								config.isServerDirty = true;
 							}
 						}
-						// If default webapp has not been found, check this one
-						if (addRootWebapp && "".equals(context.getPath())) {
-							// A default webapp is being deployed, don't add one
-							addRootWebapp = false;
-						}
-						
 					}
 				}
 			}
+			// If errors are present, return status
+			if (!ms.isOK())
+				return ms;
 
 			if (addRootWebapp) {
 				// Add a context for the default webapp
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServerBehaviour.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServerBehaviour.java
index 881e51d..57d5fe8 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServerBehaviour.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServerBehaviour.java
@@ -227,8 +227,10 @@
 		if (status != null && !status.isOK())
 			throw new CoreException(status);
 		
-		getTomcatConfiguration().localizeConfiguration(confDir, getServerDeployDirectory(),
+		status = getTomcatConfiguration().localizeConfiguration(confDir, getServerDeployDirectory(),
 				getTomcatServer(), ProgressUtil.getSubMonitorFor(monitor, 100));
+		if (status != null && !status.isOK())
+			throw new CoreException(status);
 		
 		monitor.done();
 		
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatVersionHelper.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatVersionHelper.java
index 19dd7a2..15961a2 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatVersionHelper.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatVersionHelper.java
@@ -609,76 +609,121 @@
 	 * @return result of operation
 	 */
 	public static IStatus localizeConfiguration(IPath baseDir, IPath deployDir, TomcatServer server, IProgressMonitor monitor) {
-		// If not deploying to "webapps", context docBase attributes need updating
-		// TODO Improve to compare with appBase value instead of hardcoded "webapps"
-		// TODO Need to add a root context if deploying to webapps but with auto-deploy off
-		if (!"webapps".equals(server.getDeployDirectory())) {
-			try {
-				if (Trace.isTraceEnabled())
-					Trace.trace(Trace.FINER, "Localizing configuration at " + baseDir);
-				monitor = ProgressUtil.getMonitorFor(monitor);
-				monitor.beginTask(Messages.publishConfigurationTask, 300);
+		try {
+			if (Trace.isTraceEnabled())
+				Trace.trace(Trace.FINER, "Localizing configuration at " + baseDir);
+			monitor = ProgressUtil.getMonitorFor(monitor);
+			monitor.beginTask(Messages.publishConfigurationTask, 300);
 
-				IPath serverXml = baseDir.append("conf/server.xml");
-				Factory factory = new Factory();
-				factory.setPackageName("org.eclipse.jst.server.tomcat.core.internal.xml.server40");
-				Server publishedServer = (Server)factory.loadDocument(
-						new FileInputStream(serverXml.toFile()));
-				ServerInstance publishedInstance = new ServerInstance(publishedServer, null, null);
-				monitor.worked(100);
+			IPath serverXml = baseDir.append("conf/server.xml");
+			Factory factory = new Factory();
+			factory.setPackageName("org.eclipse.jst.server.tomcat.core.internal.xml.server40");
+			Server publishedServer = (Server)factory.loadDocument(
+					new FileInputStream(serverXml.toFile()));
+			ServerInstance publishedInstance = new ServerInstance(publishedServer, null, null);
+			monitor.worked(100);
 
-				if (monitor.isCanceled())
-					return Status.CANCEL_STATUS;
-				
-				boolean modified = false;
+			if (monitor.isCanceled())
+				return Status.CANCEL_STATUS;
+			
+			boolean modified = false;
 
-				// Only add root module if running in a test env (i.e. not on the installation)
-				boolean addRootWebapp = server.isTestEnvironment();
-				
-				Context [] contexts = publishedInstance.getContexts();
-				if (contexts != null) {
-					for (int i = 0; i < contexts.length; i++) {
-						Context context = contexts[i];
+			// Only add root module if running in a test env (i.e. not on the installation)
+			boolean addRootWebapp = server.isTestEnvironment();
+			
+			// If not deploying to "webapps", context docBase attributes need updating
+			// TODO Improve to compare with appBase value instead of hardcoded "webapps"
+			boolean deployingToAppBase = "webapps".equals(server.getDeployDirectory());
+			
+			Map pathMap = new HashMap();
+			
+			MultiStatus ms = new MultiStatus(TomcatPlugin.PLUGIN_ID, 0, 
+					NLS.bind(Messages.errorPublishServer, server.getServer().getName()), null);
+			Context [] contexts = publishedInstance.getContexts();
+			if (contexts != null) {
+				for (int i = 0; i < contexts.length; i++) {
+					Context context = contexts[i];
+					// Normalize path and check for duplicates
+					String path = context.getPath();
+					if (path != null) {
+						// Save a copy of original in case it's "/"
+						String origPath = path;
+						// Normalize "/" to ""
+						if ("/".equals(path)) {
+							if (Trace.isTraceEnabled())
+								Trace.trace(Trace.FINER, "Context path is being changed from \"/\" to \"\".");
+							path = "";
+							context.setPath(path);
+							modified = true;
+						}
+
+						// Context paths that are the same or differ only in case are not allowed
+						String lcPath = path.toLowerCase();
+						if (!pathMap.containsKey(lcPath)) {
+							pathMap.put(lcPath, origPath);
+						}
+						else {
+							String otherPath = (String)pathMap.get(lcPath);
+							IStatus s = new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID,
+									origPath.equals(otherPath) ? NLS.bind(Messages.errorPublishPathDup, origPath) 
+											: NLS.bind(Messages.errorPublishPathConflict, origPath, otherPath));
+							ms.add(s);
+						}
+					}
+					else {
+						IStatus s = new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID,
+								Messages.errorPublishPathMissing);
+						ms.add(s);
+					}
+
+					// If default webapp has not been found, check this one
+					// TODO Need to add a root context if deploying to webapps but with auto-deploy off
+					if (addRootWebapp && "".equals(context.getPath())) {
+						// A default webapp is being deployed, don't add one
+						addRootWebapp = false;
+					}
+
+					// If not deploying to appBase, convert to absolute path under deploy dir
+					if (!deployingToAppBase) {
 						String source = context.getSource();
 						if (source != null && source.length() > 0 )	{
 							context.setDocBase(deployDir.append(context.getDocBase()).toOSString());
 							modified = true;
 						}
-						// If default webapp has not been found, check this one
-						if (addRootWebapp && "".equals(context.getPath())) {
-							// A default webapp is being deployed, don't add one
-							addRootWebapp = false;
-						}
 					}
 				}
-				if (addRootWebapp) {
-					// Add a context for the default webapp
-					Context rootContext = publishedInstance.createContext(0);
-					rootContext.setPath("");
-					rootContext.setDocBase(deployDir.append("ROOT").toOSString());
-					rootContext.setReloadable("false");
-					modified = true;
-				}
-				monitor.worked(100);
+			}
+			// If errors are present, return status
+			if (!ms.isOK())
+				return ms;
+			
+			if (addRootWebapp) {
+				// Add a context for the default webapp
+				Context rootContext = publishedInstance.createContext(0);
+				rootContext.setPath("");
+				rootContext.setDocBase(deployDir.append("ROOT").toOSString());
+				rootContext.setReloadable("false");
+				modified = true;
+			}
+			monitor.worked(100);
 
-				if (monitor.isCanceled())
-					return Status.CANCEL_STATUS;
-				
-				if (modified) {
-					monitor.subTask(Messages.savingContextConfigTask);
-					factory.save(serverXml.toOSString());
-				}
-				monitor.worked(100);
-				if (Trace.isTraceEnabled())
-					Trace.trace(Trace.FINER, "Context docBase settings updated in server.xml.");
+			if (monitor.isCanceled())
+				return Status.CANCEL_STATUS;
+			
+			if (modified) {
+				monitor.subTask(Messages.savingContextConfigTask);
+				factory.save(serverXml.toOSString());
 			}
-			catch (Exception e) {
-				Trace.trace(Trace.WARNING, "Could not localize server configuration published to " + baseDir.toOSString() + ": " + e.getMessage());
-				return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorPublishConfiguration, new String[] {e.getLocalizedMessage()}), e);
-			}
-			finally {
-				monitor.done();
-			}
+			monitor.worked(100);
+			if (Trace.isTraceEnabled())
+				Trace.trace(Trace.FINER, "Context docBase settings updated in server.xml.");
+		}
+		catch (Exception e) {
+			Trace.trace(Trace.WARNING, "Could not localize server configuration published to " + baseDir.toOSString() + ": " + e.getMessage());
+			return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorPublishConfiguration, new String[] {e.getLocalizedMessage()}), e);
+		}
+		finally {
+			monitor.done();
 		}
 		return Status.OK_STATUS;
 	}