[563349] Add initial support for Tomcat 10

Includes version bump for WebTools 3.20.

Change-Id: I3a9b0790963edda5223bd6396a4c3e027e70d883
diff --git a/features/org.eclipse.jst.server_adapters.ext.feature/feature.xml b/features/org.eclipse.jst.server_adapters.ext.feature/feature.xml
index 4506bde..3e14d2b 100644
--- a/features/org.eclipse.jst.server_adapters.ext.feature/feature.xml
+++ b/features/org.eclipse.jst.server_adapters.ext.feature/feature.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!--

-    Copyright (c) 2009, 2019 IBM Corporation and others.

+    Copyright (c) 2009, 2020 IBM Corporation and others.

     This program and the accompanying materials

     are made available under the terms of the Eclipse Public License 2.0

     which accompanies this distribution, and is available at

@@ -14,7 +14,7 @@
 <feature

       id="org.eclipse.jst.server_adapters.ext.feature"

       label="%featureName"

-      version="3.3.800.qualifier"

+      version="3.3.900.qualifier"

       provider-name="%providerName"

       license-feature="org.eclipse.license"

       license-feature-version="1.0.1.qualifier">

diff --git a/features/org.eclipse.jst.server_adapters.ext.feature/pom.xml b/features/org.eclipse.jst.server_adapters.ext.feature/pom.xml
index 03097f8..dc88428 100644
--- a/features/org.eclipse.jst.server_adapters.ext.feature/pom.xml
+++ b/features/org.eclipse.jst.server_adapters.ext.feature/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!--

-  Copyright (c) 2012, 2018 Eclipse Foundation and others.

+  Copyright (c) 2012, 2020 Eclipse Foundation and others.

   All rights reserved. This program and the accompanying materials

   are made available under the terms of the Eclipse Distribution License v1.0

   which accompanies this distribution, and is available at

@@ -22,7 +22,7 @@
 

   <groupId>org.eclipse.webtools.servertools</groupId>

   <artifactId>org.eclipse.jst.server_adapters.ext.feature</artifactId>

-  <version>3.3.800-SNAPSHOT</version>

+  <version>3.3.900-SNAPSHOT</version>

   <packaging>eclipse-feature</packaging>

 

   <build>

diff --git a/features/org.eclipse.jst.server_adapters.ext.sdk.feature/feature.xml b/features/org.eclipse.jst.server_adapters.ext.sdk.feature/feature.xml
index 4547899..cb60f31 100644
--- a/features/org.eclipse.jst.server_adapters.ext.sdk.feature/feature.xml
+++ b/features/org.eclipse.jst.server_adapters.ext.sdk.feature/feature.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!--

-    Copyright (c) 2009, 2019 IBM Corporation and others.

+    Copyright (c) 2009, 2020 IBM Corporation and others.

     This program and the accompanying materials

     are made available under the terms of the Eclipse Public License 2.0

     which accompanies this distribution, and is available at

@@ -14,7 +14,7 @@
 <feature

       id="org.eclipse.jst.server_adapters.ext.sdk.feature"

       label="%featureName"

-      version="3.3.800.qualifier"

+      version="3.3.900.qualifier"

       provider-name="%providerName"

       license-feature="org.eclipse.license"

       license-feature-version="1.0.1.qualifier">

diff --git a/features/org.eclipse.jst.server_adapters.ext.sdk.feature/pom.xml b/features/org.eclipse.jst.server_adapters.ext.sdk.feature/pom.xml
index c2d2ea9..ecbb30f 100644
--- a/features/org.eclipse.jst.server_adapters.ext.sdk.feature/pom.xml
+++ b/features/org.eclipse.jst.server_adapters.ext.sdk.feature/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!--

-  Copyright (c) 2012, 2018 Eclipse Foundation and others.

+  Copyright (c) 2012, 2020 Eclipse Foundation and others.

   All rights reserved. This program and the accompanying materials

   are made available under the terms of the Eclipse Distribution License v1.0

   which accompanies this distribution, and is available at

@@ -8,7 +8,7 @@
  

   Contributors:

     Thanh Ha (Eclipse Foundation) - initial implementation

--->
+-->

 

 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

@@ -22,6 +22,6 @@
 

   <groupId>org.eclipse.webtools.servertools</groupId>

   <artifactId>org.eclipse.jst.server_adapters.ext.sdk.feature</artifactId>

-  <version>3.3.800-SNAPSHOT</version>

+  <version>3.3.900-SNAPSHOT</version>

   <packaging>eclipse-feature</packaging>

 </project>

diff --git a/plugins/org.eclipse.jst.server.tomcat.core/AddTomcat.md b/plugins/org.eclipse.jst.server.tomcat.core/AddTomcat.md
new file mode 100644
index 0000000..cfc24b3
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/AddTomcat.md
@@ -0,0 +1,41 @@
+# Steps to Add a New Version of Tomcat
+
+This document describes how to add a new version of Tomcat to Eclipse WTP.  It is meant as a guide. For more details, refer to commits to prior versions. Changes to Tomcat that require refactoring of the current implementation is beyond the scope of this document. It is assumed that the new Tomcat works the same as older versions to the extent that the current ServerTools implementation still functions adequately.
+
+When modifying files, specify the current year in the copyright headers where present.
+
+### Modifications to plugins/org.eclipse.jst.server.tomcat.core
+
+1. Modify **plugin.properties** to add properties strings for the new version of Tomcat. Use existing properties as a template and make appropriate changes.  Update the **runtimeTypeTomcat???Description** value to include the new specifications that this version supports.
+2. Modify **plugin.xml** to add new configuration elements. Add new elements using existing ones as a template and make appropriate changes. Be sure to update **id** values appropriately.
+    1. Add a new **runtimeType** to the **org.eclipse.wst.server.core.runtimeTypes** extension. In the new runtimeType, the **version** list in the **moduleType** element should include the new version that this Tomcat supports, provided Eclipse has support for it. If not yet supported, it may need to be added at a later time. To check, locate the *webtools.javaee* Git repository. Examine the *plugin.xml* for the *plugins/org.eclipse.jst.jee.web project*.
+    2. Add a new **serverType** to the **org.eclipse.wst.server.core.serverTypes** extension. Besure to update the **runtimeTypeId** to match the id of the runtimeType added in step 1.
+    3. Add a new **runtime-component-version** to the **org.eclipse.wst.common.project.facet.core.runtimes** extension. Also add a **supported** element specifying the new version for its **runtime-component**.
+    4. Add a new **runtimeFacetMapping** to the **org.eclipse.jst.server.core.runtimeFacetMappings** extension.
+3. Modify **Messages.java** and **Messages.properties** to add strings for **errorJRETomcat???** and **errorSpec???**. Update the content of the strings as needed per Tomcat documention, such as the minimum version of the JRE that can be used.
+4. Modify **TomcatPlugin.java** to add a new **TOMCAT_???** string constant. Then modify its **getTomcatVersionHandler()** method to return the appropriate **Tomcat???Handler** which will be created next.
+5. Create a new **Tomcat???Handler** class by copying an existing one. 
+    1. Modify the **verifyInstallPath()** method to use the new **TomcatPlugin.TOMCAT_???** string constant.
+    2. Modify the **canAddModule()** to specify the appropriate **Messages.errorSpec???** constant. Also add any supported module version comparisons to the **if** statement.
+    3. Update the version found in strings and comments to refer to the new version.
+6. Create a new **Tomcat???Configuration** class by copying an existing one. Update the version found in strings and comments to refer to the new version.  TODO: Add support for HTTP2?
+7. Create a new **Tomcat???PublishModuleVisitor** class by copying an existing one. Update the version found in strings and comments to refer to the new version.
+8. Modify  **TomcatRuntime.java** to update the **validate()** method to support the new Tomcat version.
+    1. Add a comparison of the **id** to the new version in the **if** statement related to the *Eclipse JDT compiler*.
+    2. Add  additional **else if** code to the end of this method to handle when the **id** matches the new Tomcat version. Update the **Messages.errorJRETomcat???** appropriately. If a JRE newer than version 8 is needed, update code appropriately.
+9. Modify **TomcatRuntimeLocator.java** to update the **runtimeTypes** string array to add the runtime id of the new Tomcat version.
+10. Modify **TomcatServer.java** to update the **getTomcatConfiguration()** and **importRuntimeConfiguration()** methods to instantiate a **Tomcat???Configuration** when the **id** matches the new Tomcat version.
+11. Modify **TomcatVersionHelper.java** to support the new Tomcat version.
+    1. Update the initialization of the **versionStringMap** to add an entry that maps the new **TomcatPlugin.TOMCAT_???** to a version string.
+    2. Update the **updateContextsToServeDirectly()** to add an **isTomcat??** boolean and **else if** code to instantiate a **Tomcat???PublishModuleVisitor** when that boolean is true.
+    3. Update the **checkCatalinaVersion()** method to include checking the **TomcatPlugin.TOMCAT_???** matching the **serverType**.
+12. Modify **TomcatRuntimeClasspathProvider.java** to support the new Tomcat version.
+    1. Update the **resolveClasspathContainer()** method appropriately. Likely just add an additional runtimeId check to the first **else if** in the method.
+    2. Modify the **getTomcatJavadocLocation()** method to return the appropriate URL for the new and prior version of Tomcat.
+    3. Modify the **getEEJavadocLocation()** method to return a URL appropriate for Javadoc related to the version of specifications for the new Tomcat version.
+
+### Modifications to plugins/org.eclipse.jst.server.tomcat.ui
+
+1. Modify **plugin.xml** to add new configuration elements.
+    1. Add a new **image** to the **org.eclipse.wst.server.ui.serverImages** extension for new runtime and server ids.
+    2. Add a new **fragment** to the **org.eclipse.wst.server.ui.wizardFragments** extension.
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/META-INF/MANIFEST.MF b/plugins/org.eclipse.jst.server.tomcat.core/META-INF/MANIFEST.MF
index 983982f..aa2ff97 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.jst.server.tomcat.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jst.server.tomcat.core; singleton:=true
-Bundle-Version: 1.1.1001.qualifier
+Bundle-Version: 1.1.1100.qualifier
 Bundle-Activator: org.eclipse.jst.server.tomcat.core.internal.TomcatPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/plugin.properties b/plugins/org.eclipse.jst.server.tomcat.core/plugin.properties
index 681b9f7..ebcec03 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/plugin.properties
+++ b/plugins/org.eclipse.jst.server.tomcat.core/plugin.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2004, 2016 IBM Corporation and others.
+# Copyright (c) 2004, 2020 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
 # which accompanies this distribution, and is available at
@@ -35,6 +35,8 @@
 runtimeTypeTomcat85Description=Apache Tomcat v8.5 supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, and 7 Web modules.
 runtimeTypeTomcat90Label=Apache Tomcat v9.0
 runtimeTypeTomcat90Description=Apache Tomcat v9.0 supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, 7, and 8 Web modules.
+runtimeTypeTomcat100Label=Apache Tomcat v10.0
+runtimeTypeTomcat100Description=Apache Tomcat v10.0 supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, 7, 8 and Jakarta EE 9 Web modules.
 
 # --------------- Servers ---------------
 tomcat32ServerType=Tomcat v3.2 Server
@@ -67,6 +69,9 @@
 tomcat90ServerType=Tomcat v9.0 Server
 tomcat90ServerDescription=Publishes and runs J2EE and Java EE Web projects and server configurations to a local Tomcat server.
 
+tomcat100ServerType=Tomcat v10.0 Server
+tomcat100ServerDescription=Publishes and runs J2EE and Java EE Web projects and server configurations to a local Tomcat server.
+
 tomcatLaunchConfigurationType=Apache Tomcat
 
 # --------------- General ---------------
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/plugin.xml b/plugins/org.eclipse.jst.server.tomcat.core/plugin.xml
index 1e57d2e..4fc9764 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/plugin.xml
+++ b/plugins/org.eclipse.jst.server.tomcat.core/plugin.xml
@@ -149,6 +149,20 @@
          types="jst.utility"
          versions="1.0"/>
     </runtimeType>
+    <runtimeType
+       id="org.eclipse.jst.server.tomcat.runtime.100"
+       name="%runtimeTypeTomcat100Label"
+       description="%runtimeTypeTomcat100Description"
+       vendor="%apache"
+       version="10.0"
+       class="org.eclipse.jst.server.tomcat.core.internal.TomcatRuntime">
+       <moduleType
+         types="jst.web"
+         versions="2.2, 2.3, 2.4, 2.5, 3.0, 3.1, 4.0"/>
+       <moduleType
+         types="jst.utility"
+         versions="1.0"/>
+    </runtimeType>
   </extension>
 
   <extension point="org.eclipse.wst.server.core.runtimeLocators">
@@ -316,6 +330,21 @@
        class="org.eclipse.jst.server.tomcat.core.internal.TomcatServer"
        behaviourClass="org.eclipse.jst.server.tomcat.core.internal.TomcatServerBehaviour">
      </serverType>
+     <serverType
+       id="org.eclipse.jst.server.tomcat.100"
+       name="%tomcat100ServerType"
+       description="%tomcat100ServerDescription"
+       supportsRemoteHosts="false"
+       runtime="true"
+       startTimeout="45000"
+       stopTimeout="15000"
+       initialState="stopped"
+       hasConfiguration="true"
+       launchConfigId="org.eclipse.jst.server.tomcat.core.launchConfigurationType"
+       runtimeTypeId="org.eclipse.jst.server.tomcat.runtime.100"
+       class="org.eclipse.jst.server.tomcat.core.internal.TomcatServer"
+       behaviourClass="org.eclipse.jst.server.tomcat.core.internal.TomcatServerBehaviour">
+     </serverType>
   </extension>
 
   <extension point="org.eclipse.wst.server.core.serverLocators">
@@ -399,6 +428,10 @@
        type="org.eclipse.jst.server.tomcat"
        version="9.0"/>
 
+    <runtime-component-version
+       type="org.eclipse.jst.server.tomcat"
+       version="10.0"/>
+
     <adapter>
       <runtime-component
          id="org.eclipse.jst.server.tomcat"/>
@@ -539,6 +572,21 @@
          id="jst.utility"
          version="1.0"/>
     </supported>
+
+    <supported>
+      <runtime-component
+         id="org.eclipse.jst.server.tomcat"
+         version="10.0"/>
+      <facet
+         id="jst.web"
+         version="2.2,2.3,2.4,2.5,3.0,3.1,4.0"/>
+      <facet
+         id="jst.webfragment"
+         version="3.0,3.1,4.0"/>
+      <facet
+         id="jst.utility"
+         version="1.0"/>
+    </supported>
   </extension>
   
   <extension point="org.eclipse.wst.common.project.facet.core.defaultFacets">
@@ -589,6 +637,10 @@
       runtimeTypeId="org.eclipse.jst.server.tomcat.runtime.90"
       runtime-component="org.eclipse.jst.server.tomcat"
       version="9.0"/>
+    <runtimeFacetMapping
+      runtimeTypeId="org.eclipse.jst.server.tomcat.runtime.100"
+      runtime-component="org.eclipse.jst.server.tomcat"
+      version="10.0"/>
   </extension>
 
   <extension point="org.eclipse.wst.server.core.installableRuntimes">
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/pom.xml b/plugins/org.eclipse.jst.server.tomcat.core/pom.xml
index fe00204..bec18b6 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/pom.xml
+++ b/plugins/org.eclipse.jst.server.tomcat.core/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright (c) 2012, 2018 Eclipse Foundation and others.
+  Copyright (c) 2012, 2020 Eclipse Foundation and others.
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
@@ -22,6 +22,6 @@
 
   <groupId>org.eclipse.webtools.servertools</groupId>
   <artifactId>org.eclipse.jst.server.tomcat.core</artifactId>
-  <version>1.1.1001-SNAPSHOT</version>
+  <version>1.1.1100-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
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 c180ede..87d5530 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2016 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -36,6 +36,7 @@
 	public static String errorJRETomcat80;
 	public static String errorJRETomcat85;
 	public static String errorJRETomcat90;
+	public static String errorJRETomcat100;
 	public static String warningJRE;
 	public static String warningCantReadConfig;
 	public static String target32runtime;
@@ -61,6 +62,7 @@
 	public static String errorSpec80;
 	public static String errorSpec85;
 	public static String errorSpec90;
+	public static String errorSpec100;
 	public static String portServer;
 	public static String runtimeDirPrepared;
 	public static String publishConfigurationTask;
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 1b43460..26d2c95 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
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2004, 2016 IBM Corporation and others.
+# Copyright (c) 2004, 2020 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
 # which accompanies this distribution, and is available at
@@ -74,6 +74,7 @@
 errorJRETomcat80=Tomcat version 8.0 requires Java SE 7 or later.  Change the JRE to one that meets this requirement.
 errorJRETomcat85=Tomcat version 8.5 requires Java SE 7 or later.  Change the JRE to one that meets this requirement.
 errorJRETomcat90=Tomcat version 9.0 requires Java SE 8 or later.  Change the JRE to one that meets this requirement.
+errorJRETomcat100=Tomcat version 10.0 requires Java SE 8 or later.  Change the JRE to one that meets this requirement.
 errorPortInvalid=The server cannot be started because one or more of the ports are invalid. Open the server editor and correct the invalid ports.
 errorPortInUse=Port {0} required by {1} is already in use. The server may already be running in another process, or a system process may be using the port. \
   To start this server you will need to stop the other process or change the port number(s).
@@ -100,6 +101,7 @@
 errorSpec80=Tomcat version 8.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, and 7 Web modules
 errorSpec85=Tomcat version 8.5 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, and 7 Web modules
 errorSpec90=Tomcat version 9.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, 7, and 8 Web modules
+errorSpec100=Tomcat version 10.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, 7, 8, and 9 Web modules
 errorDuplicateContextRoot=Two or more Web modules defined in the configuration have the same context root ({0}). \
   To start this server you will need to remove the duplicate(s).
 errorCouldNotLoadContextXml=Could not load the context configuration for the {0} context due to a syntax error or other exception.
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100Configuration.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100Configuration.java
new file mode 100644
index 0000000..87f0e20
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100Configuration.java
@@ -0,0 +1,712 @@
+/**********************************************************************
+ * Copyright (c) 2020 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *    IBM Corporation - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jst.server.tomcat.core.internal.xml.Factory;
+import org.eclipse.jst.server.tomcat.core.internal.xml.XMLUtil;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Connector;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Context;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Listener;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Server;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.ServerInstance;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Service;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.wst.server.core.ServerPort;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+/**
+ * Tomcat v10.0 server configuration.
+ */
+public class Tomcat100Configuration extends TomcatConfiguration {
+	protected static final String DEFAULT_SERVICE = "Catalina";
+	protected static final String EOL = System.getProperty("line.separator");
+	protected Server server;
+	protected ServerInstance serverInstance;
+	protected Factory serverFactory;
+	protected boolean isServerDirty;
+
+	protected WebAppDocument webAppDocument;
+
+	protected Document contextDocument;
+
+	protected Document tomcatUsersDocument;
+
+	protected String policyFile;
+
+	protected String propertiesFile;
+	
+	protected static final Map<String, String> protocolHandlerMap = new HashMap<String, String>();
+	static {
+		protocolHandlerMap.put("org.apache.coyote.http11.Http11Protocol", "HTTP/1.1");
+		protocolHandlerMap.put("org.apache.coyote.http11.Http11NioProtocol", "HTTP/1.1");
+		protocolHandlerMap.put("org.apache.coyote.http11.Http11AprProtocol", "HTTP/1.1");
+		protocolHandlerMap.put("org.apache.coyote.ajp.AjpAprProtocol", "AJP/1.3");
+		protocolHandlerMap.put("org.apache.jk.server.JkCoyoteHandler", "AJP/1.3");
+	}
+	
+	/**
+	 * Tomcat100Configuration constructor.
+	 * 
+	 * @param path a path
+	 */
+	public Tomcat100Configuration(IFolder path) {
+		super(path);
+	}
+
+	/**
+	 * Return the port number.
+	 * @return int
+	 */
+	public ServerPort getMainPort() {
+		Iterator iterator = getServerPorts().iterator();
+		while (iterator.hasNext()) {
+			ServerPort port = (ServerPort) iterator.next();
+			// Return only an HTTP port from the selected Service
+			if (port.getProtocol().toLowerCase().equals("http") && port.getId().indexOf('/') < 0)
+				return port;
+		}
+		return null;
+	}
+	
+	/**
+	 * Returns the mime mappings.
+	 * @return java.util.List
+	 */
+	public List getMimeMappings() {
+		return webAppDocument.getMimeMappings();
+	}
+
+	/**
+	 * Returns a list of ServerPorts that this configuration uses.
+	 *
+	 * @return java.util.List
+	 */
+	public List getServerPorts() {
+		List<ServerPort> ports = new ArrayList<ServerPort>();
+	
+		// first add server port
+		try {
+			int port = Integer.parseInt(server.getPort());
+			ports.add(new ServerPort("server", Messages.portServer, port, "TCPIP"));
+		} catch (Exception e) {
+			// ignore
+		}
+	
+		// add connectors
+		try {
+			String instanceServiceName = serverInstance.getService().getName();
+			int size = server.getServiceCount();
+			for (int i = 0; i < size; i++) {
+				Service service = server.getService(i);
+				int size2 = service.getConnectorCount();
+				for (int j = 0; j < size2; j++) {
+					Connector connector = service.getConnector(j);
+					String name = "HTTP/1.1";
+					String protocol2 = "HTTP";
+					boolean advanced = true;
+					String[] contentTypes = null;
+					int port = -1;
+					try {
+						port = Integer.parseInt(connector.getPort());
+					} catch (Exception e) {
+						// ignore
+					}
+					String protocol = connector.getProtocol();
+					if (protocol != null && protocol.length() > 0) {
+						if (protocol.startsWith("HTTP")) {
+							name = protocol;
+						}
+						else if (protocol.startsWith("AJP")) {
+							name = protocol;
+							protocol2 = "AJP"; 
+						}
+						else {
+							// Get Tomcat equivalent name if protocol handler class specified
+							name = protocolHandlerMap.get(protocol);
+							if (name != null) {
+								// Prepare simple protocol string for ServerPort protocol
+								int index = name.indexOf('/');
+								if (index > 0)
+									protocol2 = name.substring(0, index);
+								else
+									protocol2 = name;
+							}
+							// Specified protocol is unknown, just use as is
+							else {
+								name = protocol;
+								protocol2 = protocol;
+							}
+						}
+					}
+					if (protocol2.toLowerCase().equals("http"))
+						contentTypes = new String[] { "web", "webservices" };
+					String secure = connector.getSecure();
+					if (secure != null && secure.length() > 0) {
+						name = "SSL";
+						protocol2 = "SSL";
+					} else
+						advanced = false;
+					String portId;
+					if (instanceServiceName != null && instanceServiceName.equals(service.getName()))
+						portId = Integer.toString(j);
+					else
+						portId = i +"/" + j;
+					ports.add(new ServerPort(portId, name, port, protocol2, contentTypes, advanced));
+				}
+			}
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Error getting server ports", e);
+		}
+		return ports;
+	}
+	
+	/**
+	 * Return a list of the web modules in this server.
+	 * @return java.util.List
+	 */
+	public List getWebModules() {
+		List<WebModule> list = new ArrayList<WebModule>();
+	
+		try {
+			Context [] contexts = serverInstance.getContexts();
+			if (contexts != null) {
+				for (int i = 0; i < contexts.length; i++) {
+					Context context = contexts[i];
+					String reload = context.getReloadable();
+					if (reload == null)
+						reload = "false";
+					WebModule module = new WebModule(context.getPath(), 
+						context.getDocBase(), context.getSource(),
+						reload.equalsIgnoreCase("true") ? true : false);
+					list.add(module);
+				}
+			}
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Error getting project refs", e);
+		}
+		return list;
+	}
+	
+	/**
+	 * @see TomcatConfiguration#getServerWorkDirectory(IPath)
+	 */
+	public IPath getServerWorkDirectory(IPath basePath) {
+		return serverInstance.getHostWorkDirectory(basePath);
+	}
+
+	/**
+	 * @see TomcatConfiguration#getContextWorkDirectory(IPath, ITomcatWebModule)
+	 */
+	public IPath getContextWorkDirectory(IPath basePath, ITomcatWebModule module) {
+		Context context = serverInstance.getContext(module.getPath());
+		if (context != null)
+			return serverInstance.getContextWorkDirectory(basePath, context);
+		
+		return null;
+	}
+
+	/**
+	 * @see TomcatConfiguration#load(IPath, IProgressMonitor)
+	 */
+	public void load(IPath path, IProgressMonitor monitor) throws CoreException {
+		try {
+			monitor = ProgressUtil.getMonitorFor(monitor);
+			monitor.beginTask(Messages.loadingTask, 7);
+			
+			// check for catalina.policy to verify that this is a v4.0 or later config
+			InputStream in = new FileInputStream(path.append("catalina.policy").toFile());
+			in.read();
+			in.close();
+			monitor.worked(1);
+
+			serverFactory = new Factory();
+			serverFactory.setPackageName("org.eclipse.jst.server.tomcat.core.internal.xml.server40");
+			server = (Server) serverFactory.loadDocument(new FileInputStream(path.append("server.xml").toFile()));
+			serverInstance = new ServerInstance(server, null, null);
+			monitor.worked(1);
+
+			webAppDocument = new WebAppDocument(path.append("web.xml"));
+			monitor.worked(1);
+			
+			File file = path.append("context.xml").toFile();
+			if (file.exists())
+				contextDocument = XMLUtil.getDocumentBuilder().parse(new InputSource(new FileInputStream(file)));
+			monitor.worked(1);
+			
+			tomcatUsersDocument = XMLUtil.getDocumentBuilder().parse(new InputSource(new FileInputStream(path.append("tomcat-users.xml").toFile())));
+			monitor.worked(1);
+			
+			// load policy file
+			policyFile = TomcatVersionHelper.getFileContents(new FileInputStream(path.append("catalina.policy").toFile()));
+			monitor.worked(1);
+
+			// load properties file
+			file = path.append("catalina.properties").toFile();
+			if (file.exists())
+				propertiesFile = TomcatVersionHelper.getFileContents(new FileInputStream(file));
+			else
+				propertiesFile = null;
+			monitor.worked(1);
+			
+			if (monitor.isCanceled())
+				return;
+			monitor.done();
+		} catch (Exception e) {
+			Trace.trace(Trace.WARNING, "Could not load Tomcat v10.0 configuration from " + path.toOSString() + ": " + e.getMessage());
+			throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorCouldNotLoadConfiguration, path.toOSString()), e));
+		}
+	}
+
+	/**
+	 * @see TomcatConfiguration#importFromPath(IPath, boolean, IProgressMonitor)
+	 */
+	public void importFromPath(IPath path, boolean isTestEnv, IProgressMonitor monitor) throws CoreException {
+		load(path, monitor);
+		
+		// for test environment, remove existing contexts since a separate
+		// catalina.base will be used
+		if (isTestEnv) {
+			while (serverInstance.removeContext(0)) {
+				// no-op
+			}
+		}
+	}
+
+	/**
+	 * @see TomcatConfiguration#load(IFolder, IProgressMonitor)
+	 */
+	public void load(IFolder folder, IProgressMonitor monitor) throws CoreException {
+		try {
+			monitor = ProgressUtil.getMonitorFor(monitor);
+			monitor.beginTask(Messages.loadingTask, 1200);
+	
+			// check for catalina.policy to verify that this is a v4.0 or later config
+			IFile file = folder.getFile("catalina.policy");
+			if (!file.exists())
+				throw new CoreException(new Status(IStatus.WARNING, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorCouldNotLoadConfiguration, folder.getFullPath().toOSString()), null));
+	
+			// load server.xml
+			file = folder.getFile("server.xml");
+			InputStream in = file.getContents();
+			serverFactory = new Factory();
+			serverFactory.setPackageName("org.eclipse.jst.server.tomcat.core.internal.xml.server40");
+			server = (Server) serverFactory.loadDocument(in);
+			serverInstance = new ServerInstance(server, null, null);
+			monitor.worked(200);
+	
+			// load web.xml
+			file = folder.getFile("web.xml");
+			webAppDocument = new WebAppDocument(file);
+			monitor.worked(200);
+	
+			// load context.xml
+			file = folder.getFile("context.xml");
+			if (file.exists()) {
+				in = file.getContents();
+				contextDocument = XMLUtil.getDocumentBuilder().parse(new InputSource(in));
+			}
+			else
+				contextDocument = null;
+			monitor.worked(200);
+		
+			// load tomcat-users.xml
+			file = folder.getFile("tomcat-users.xml");
+			in = file.getContents();
+			
+			tomcatUsersDocument = XMLUtil.getDocumentBuilder().parse(new InputSource(in));
+			monitor.worked(200);
+		
+			// load catalina.policy
+			file = folder.getFile("catalina.policy");
+			in = file.getContents();
+			policyFile = TomcatVersionHelper.getFileContents(in);
+			monitor.worked(200);
+	
+			// load catalina.properties
+			file = folder.getFile("catalina.properties");
+			if (file.exists()) {
+				in = file.getContents();
+				propertiesFile = TomcatVersionHelper.getFileContents(in);
+			}
+			else
+				propertiesFile = null;
+			monitor.worked(200);
+			
+			if (monitor.isCanceled())
+				throw new Exception("Cancelled");
+			monitor.done();
+		} catch (Exception e) {
+			Trace.trace(Trace.WARNING, "Could not reload Tomcat v10.0 configuration from: " + folder.getFullPath() + ": " + e.getMessage());
+			throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorCouldNotLoadConfiguration, folder.getFullPath().toOSString()), e));
+		}
+	}
+
+	/**
+	 * Save to the given directory.
+	 * @param path a path
+	 * @param forceDirty boolean
+	 * @param monitor a progress monitor
+	 * @exception CoreException
+	 */
+	protected void save(IPath path, boolean forceDirty, IProgressMonitor monitor) throws CoreException {
+		try {
+			monitor = ProgressUtil.getMonitorFor(monitor);
+			monitor.beginTask(Messages.savingTask, 5);
+			
+			// make sure directory exists
+			if (!path.toFile().exists()) {
+				forceDirty = true;
+				path.toFile().mkdir();
+			}
+			monitor.worked(1);
+			
+			// save files
+			if (forceDirty || isServerDirty) {
+				serverFactory.save(path.append("server.xml").toOSString());
+				isServerDirty = false;
+			}
+			monitor.worked(1);
+			
+			webAppDocument.save(path.append("web.xml").toOSString(), forceDirty);
+			monitor.worked(1);
+			
+			if (forceDirty && contextDocument != null)
+				XMLUtil.save(path.append("context.xml").toOSString(), contextDocument);
+			monitor.worked(1);
+			
+			if (forceDirty)
+				XMLUtil.save(path.append("tomcat-users.xml").toOSString(), tomcatUsersDocument);
+			monitor.worked(1);
+			
+			if (forceDirty) {
+				BufferedWriter bw = new BufferedWriter(new FileWriter(path.append("catalina.policy").toFile()));
+				bw.write(policyFile);
+				bw.close();
+			}
+			monitor.worked(1);
+			if (propertiesFile != null && forceDirty) {
+				BufferedWriter bw = new BufferedWriter(new FileWriter(path.append("catalina.properties").toFile()));
+				bw.write(propertiesFile);
+				bw.close();
+			}
+			monitor.worked(1);
+			
+			if (monitor.isCanceled())
+				return;
+			monitor.done();
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Could not save Tomcat v10.0 configuration to " + path, e);
+			throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorCouldNotSaveConfiguration, new String[] {e.getLocalizedMessage()}), e));
+		}
+	}
+
+	/**
+	 * Save to the given directory.  All configuration files
+	 * are forced to be saved.
+	 * 
+	 * @param path Desination path for the configuration files.
+	 * @param monitor A progress monitor
+	 * @exception CoreException
+	 */
+	public void save(IPath path, IProgressMonitor monitor) throws CoreException {
+		save(path, true, monitor);
+	}
+
+	/**
+	 * Save the information held by this object to the given directory.
+	 *
+	 * @param folder a folder
+	 * @param monitor a progress monitor
+	 * @throws CoreException
+	 */
+	public void save(IFolder folder, IProgressMonitor monitor) throws CoreException {
+		try {
+			monitor = ProgressUtil.getMonitorFor(monitor);
+			monitor.beginTask(Messages.savingTask, 1200);
+	
+			// save server.xml
+			byte[] data = serverFactory.getContents();
+			InputStream in = new ByteArrayInputStream(data);
+			IFile file = folder.getFile("server.xml");
+			if (file.exists()) {
+				if (isServerDirty)
+					file.setContents(in, true, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+				else
+					monitor.worked(200);
+			} else
+				file.create(in, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			isServerDirty = false;
+			
+			// save web.xml
+			webAppDocument.save(folder.getFile("web.xml"), ProgressUtil.getSubMonitorFor(monitor, 200));
+			
+			// save context.xml
+			if (contextDocument != null) {
+				data = XMLUtil.getContents(contextDocument);
+				in = new ByteArrayInputStream(data);
+				file = folder.getFile("context.xml");
+				if (file.exists())
+					monitor.worked(200);
+					//file.setContents(in, true, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+				else
+					file.create(in, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			}
+			
+			// save tomcat-users.xml
+			data = XMLUtil.getContents(tomcatUsersDocument);
+			in = new ByteArrayInputStream(data);
+			file = folder.getFile("tomcat-users.xml");
+			if (file.exists())
+				monitor.worked(200);
+				//file.setContents(in, true, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			else
+				file.create(in, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			
+			// save catalina.policy
+			in = new ByteArrayInputStream(policyFile.getBytes());
+			file = folder.getFile("catalina.policy");
+			if (file.exists())
+				monitor.worked(200);
+				//file.setContents(in, true, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			else
+				file.create(in, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			
+			// save catalina.properties
+			if (propertiesFile != null) {
+				in = new ByteArrayInputStream(propertiesFile.getBytes());
+				file = folder.getFile("catalina.properties");
+				if (file.exists())
+					monitor.worked(200);
+					//file.setContents(in, true, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+				else
+					file.create(in, true, ProgressUtil.getSubMonitorFor(monitor, 200));
+			} else
+				monitor.worked(200);
+			
+			if (monitor.isCanceled())
+				return;
+			monitor.done();
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Could not save Tomcat v10.0 configuration to " + folder.toString(), e);
+			throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorCouldNotSaveConfiguration, new String[] {e.getLocalizedMessage()}), e));
+		}
+	}
+
+	protected static boolean hasMDBListener(Server server) {
+		if (server == null)
+			return false;
+		
+		int count = server.getListenerCount();
+		if (count == 0)
+			return false;
+			
+		for (int i = 0; i < count; i++) {
+			Listener listener = server.getListener(i);
+			if (listener != null && listener.getClassName() != null && listener.getClassName().indexOf("mbean") >= 0)
+				return true;
+		}
+		return false;
+	}
+	
+	/**
+	 * @see ITomcatConfigurationWorkingCopy#addMimeMapping(int, IMimeMapping)
+	 */
+	public void addMimeMapping(int index, IMimeMapping map) {
+		webAppDocument.addMimeMapping(index, map);
+		firePropertyChangeEvent(ADD_MAPPING_PROPERTY, new Integer(index), map);
+	}
+
+	/**
+	 * @see ITomcatConfigurationWorkingCopy#addWebModule(int, ITomcatWebModule)
+	 */
+	public void addWebModule(int index, ITomcatWebModule module) {
+		try {
+			Context context = serverInstance.createContext(index);
+			if (context != null) {
+				context.setDocBase(module.getDocumentBase());
+				context.setPath(module.getPath());
+				context.setReloadable(module.isReloadable() ? "true" : "false");
+				if (module.getMemento() != null && module.getMemento().length() > 0)
+					context.setSource(module.getMemento());
+				isServerDirty = true;
+				firePropertyChangeEvent(ADD_WEB_MODULE_PROPERTY, null, module);
+			}
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Error adding web module " + module.getPath(), e);
+		}
+	}
+
+	/**
+	 * Change the extension of a mime mapping.
+	 * 
+	 * @param index
+	 * @param map
+	 */
+	public void modifyMimeMapping(int index, IMimeMapping map) {
+		webAppDocument.modifyMimeMapping(index, map);
+		firePropertyChangeEvent(MODIFY_MAPPING_PROPERTY, new Integer(index), map);
+	}
+
+	/**
+	 * Modify the port with the given id.
+	 *
+	 * @param id java.lang.String
+	 * @param port int
+	 */
+	public void modifyServerPort(String id, int port) {
+		try {
+			if ("server".equals(id)) {
+				server.setPort(port + "");
+				isServerDirty = true;
+				firePropertyChangeEvent(MODIFY_PORT_PROPERTY, id, new Integer(port));
+				return;
+			}
+	
+			int i = id.indexOf("/");
+			// If a connector in the instance Service
+			if (i < 0) {
+				int connNum = Integer.parseInt(id);
+				Connector connector = serverInstance.getConnector(connNum);
+				if (connector != null) {
+					connector.setPort(port + "");
+					isServerDirty = true;
+					firePropertyChangeEvent(MODIFY_PORT_PROPERTY, id, new Integer(port));
+				}
+			}
+			// Else a connector in another Service
+			else {
+				int servNum = Integer.parseInt(id.substring(0, i));
+				int connNum = Integer.parseInt(id.substring(i + 1));
+				
+				Service service = server.getService(servNum);
+				Connector connector = service.getConnector(connNum);
+				connector.setPort(port + "");
+				isServerDirty = true;
+				firePropertyChangeEvent(MODIFY_PORT_PROPERTY, id, new Integer(port));
+			}
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Error modifying server port " + id, e);
+		}
+	}
+	/**
+	 * Change a web module.
+	 * @param index int
+	 * @param docBase java.lang.String
+	 * @param path java.lang.String
+	 * @param reloadable boolean
+	 */
+	public void modifyWebModule(int index, String docBase, String path, boolean reloadable) {
+		try {
+			Context context = serverInstance.getContext(index);
+			if (context != null) {
+				context.setPath(path);
+				context.setDocBase(docBase);
+				context.setReloadable(reloadable ? "true" : "false");
+				isServerDirty = true;
+				WebModule module = new WebModule(path, docBase, null, reloadable);
+				firePropertyChangeEvent(MODIFY_WEB_MODULE_PROPERTY, new Integer(index), module);
+			}
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Error modifying web module " + index, e);
+		}
+	}
+
+	/**
+	 * Removes a mime mapping.
+	 * @param index int
+	 */
+	public void removeMimeMapping(int index) {
+		webAppDocument.removeMimeMapping(index);
+		firePropertyChangeEvent(REMOVE_MAPPING_PROPERTY, null, new Integer(index));
+	}
+
+	/**
+	 * Removes a web module.
+	 * @param index int
+	 */
+	public void removeWebModule(int index) {
+		try {
+			serverInstance.removeContext(index);
+			isServerDirty = true;
+			firePropertyChangeEvent(REMOVE_WEB_MODULE_PROPERTY, null, new Integer(index));
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Error removing module ref " + index, e);
+		}
+	}
+
+	/**
+	 * Add context configuration found in META-INF/context.xml files
+	 * present in projects to published server.xml.
+	 * 
+	 * @param baseDir path to catalina instance directory
+	 * @param deployDir path to deployment directory
+	 * @param monitor a progress monitor or null
+	 * @return result of operation
+	 */
+	protected IStatus publishContextConfig(IPath baseDir, IPath deployDir, IProgressMonitor monitor) {
+		return TomcatVersionHelper.publishCatalinaContextConfig(baseDir, deployDir, monitor);
+	}
+	
+	/**
+	 * Update contexts in server.xml to serve projects directly without
+	 * publishing.
+	 * 
+	 * @param baseDir path to catalina instance directory
+	 * @param monitor a progress monitor or null
+	 * @return result of operation
+	 */
+	protected IStatus updateContextsToServeDirectly(IPath baseDir, String tomcatVersion, String loader, IProgressMonitor monitor) {
+		return TomcatVersionHelper.updateContextsToServeDirectly(baseDir, tomcatVersion, loader, true, monitor);
+	}
+
+	/**
+	 * Cleanup the server instance.  This consists of deleting the work
+	 * directory associated with Contexts that are going away in the
+	 * up coming publish.
+	 * 
+	 * @param baseDir path to server instance directory, i.e. catalina.base
+	 * @param installDir path to server installation directory (not currently used)
+	 * @param monitor a progress monitor or null
+	 * @return MultiStatus containing results of the cleanup operation
+	 */
+	protected IStatus cleanupServer(IPath baseDir, IPath installDir, boolean removeKeptContextFiles, IProgressMonitor monitor) {
+		List modules = getWebModules();
+		return TomcatVersionHelper.cleanupCatalinaServer(baseDir, installDir, removeKeptContextFiles, modules, monitor);
+	}
+
+	/**
+	 * @see TomcatConfiguration#localizeConfiguration(IPath, IPath, TomcatServer, IProgressMonitor)
+	 */
+	public IStatus localizeConfiguration(IPath baseDir, IPath deployDir, TomcatServer tomcatServer, IProgressMonitor monitor) {
+		return TomcatVersionHelper.localizeConfiguration(baseDir, deployDir, tomcatServer, monitor);
+	}
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100Handler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100Handler.java
new file mode 100644
index 0000000..530d4d4
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100Handler.java
@@ -0,0 +1,190 @@
+/**********************************************************************
+ * Copyright (c) 2020 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *    IBM Corporation - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
+import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.wst.server.core.IModule;
+/**
+ * Tomcat 100 handler.
+ */
+public class Tomcat100Handler implements ITomcatVersionHandler {
+	/**
+	 * @see ITomcatVersionHandler#verifyInstallPath(IPath)
+	 */
+	public IStatus verifyInstallPath(IPath installPath) {
+		IStatus result = TomcatVersionHelper.checkCatalinaVersion(installPath, TomcatPlugin.TOMCAT_100);
+		// If check was canceled, use folder check
+		if (result.getSeverity() == IStatus.CANCEL) {
+			result = TomcatPlugin.verifyInstallPathWithFolderCheck(installPath, TomcatPlugin.TOMCAT_100);
+		}
+		return result;
+	}
+	
+	/**
+	 * @see ITomcatVersionHandler#getRuntimeClass()
+	 */
+	public String getRuntimeClass() {
+		return "org.apache.catalina.startup.Bootstrap";
+	}
+	
+	/**
+	 * @see ITomcatVersionHandler#getRuntimeClasspath(IPath, IPath)
+	 */
+	public List getRuntimeClasspath(IPath installPath, IPath configPath) {
+		List<IRuntimeClasspathEntry> cp = new ArrayList<IRuntimeClasspathEntry>();
+		
+		// 10.0 - add bootstrap.jar and tomcat-juli.jar from the Tomcat bin directory
+		IPath binPath = installPath.append("bin");
+		if (binPath.toFile().exists()) {
+			IPath path = binPath.append("bootstrap.jar");
+			cp.add(JavaRuntime.newArchiveRuntimeClasspathEntry(path));
+			// Add tomcat-juli.jar if it exists
+			path = binPath.append("tomcat-juli.jar");
+			if (path.toFile().exists()) {
+				cp.add(JavaRuntime.newArchiveRuntimeClasspathEntry(path));
+			}
+			// If tomcat-juli.jar is not found in the install, check the config directory
+			else if (configPath != null){
+				path = configPath.append("bin/tomcat-juli.jar");
+				if (path.toFile().exists()) {
+					cp.add(JavaRuntime.newArchiveRuntimeClasspathEntry(path));
+				}
+			}
+		}
+		
+		return cp;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getRuntimeProgramArguments(IPath, boolean, boolean)
+	 */
+	public String[] getRuntimeProgramArguments(IPath configPath, boolean debug, boolean starting) {
+		List<String> list = new ArrayList<String>();
+
+		if (starting)
+			list.add("start");
+		else
+			list.add("stop");
+		
+		String[] temp = new String[list.size()];
+		list.toArray(temp);
+		return temp;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getExcludedRuntimeProgramArguments(boolean, boolean)
+	 */
+	public String[] getExcludedRuntimeProgramArguments(boolean debug, boolean starting) {
+		return null;
+	}
+	
+	/**
+	 * @see ITomcatVersionHandler#getRuntimeVMArguments(IPath, IPath, IPath, boolean)
+	 */
+	public String[] getRuntimeVMArguments(IPath installPath, IPath configPath, IPath deployPath, boolean isTestEnv) {
+		return TomcatVersionHelper.getCatalinaVMArguments(installPath, configPath, deployPath, isTestEnv);
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getRuntimePolicyFile(IPath)
+	 */
+	public String getRuntimePolicyFile(IPath configPath) {
+		return configPath.append("conf").append("catalina.policy").toOSString();
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#canAddModule(IModule)
+	 */
+	public IStatus canAddModule(IModule module) {
+		String version = module.getModuleType().getVersion();
+		if ("2.2".equals(version) || "2.3".equals(version) || "2.4".equals(version) || "2.5".equals(version)
+				|| "3.0".equals(version) || "3.1".equals(version) || "4.0".equals(version))
+			return Status.OK_STATUS;
+		
+		return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorSpec100, null);
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getRuntimeBaseDirectory(TomcatServer)
+	 */
+	public IPath getRuntimeBaseDirectory(TomcatServer server) {
+		return TomcatVersionHelper.getStandardBaseDirectory(server);
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#prepareRuntimeDirectory(IPath)
+	 */
+	public IStatus prepareRuntimeDirectory(IPath baseDir) {
+		return TomcatVersionHelper.createCatalinaInstanceDirectory(baseDir);
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#prepareDeployDirectory(IPath)
+	 */
+	public IStatus prepareDeployDirectory(IPath deployPath) {
+		return TomcatVersionHelper.createDeploymentDirectory(deployPath,
+				TomcatVersionHelper.DEFAULT_WEBXML_SERVLET25);
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#prepareForServingDirectly(IPath, TomcatServer)
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server, String tomcatVersion) {
+		// Nothing beyond configuration required for Tomcat 10
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getSharedLoader(IPath)
+	 */
+	public String getSharedLoader(IPath baseDir) {
+		return "common";
+	}
+	
+	/**
+	 * Returns true since Tomcat 10.x supports this feature.
+	 * 
+	 * @return true since feature is supported
+	 */
+	public boolean supportsServeModulesWithoutPublish() {
+		return true;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsDebugArgument()
+	 */
+	public boolean supportsDebugArgument() {
+		return false;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsSeparateContextFiles()
+	 */
+	public boolean supportsSeparateContextFiles() {
+		return true;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getEndorsedDirectories(IPath)
+	 */
+	public String getEndorsedDirectories(IPath installPath) {
+		return installPath.append("endorsed").toOSString();
+	}	
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100PublishModuleVisitor.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100PublishModuleVisitor.java
new file mode 100644
index 0000000..c6d450a
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat100PublishModuleVisitor.java
@@ -0,0 +1,272 @@
+/**********************************************************************
+ * Copyright (c) 2020 SAS Institute and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *    SAS Institute - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal;
+
+import java.io.File;
+import java.io.FileFilter;
+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.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Context;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.JarResources;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.PostResources;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.PreResources;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.ServerInstance;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
+import org.eclipse.wst.common.componentcore.resources.IVirtualResource;
+import org.eclipse.wst.server.core.IModule;
+import org.eclipse.wst.server.core.ServerUtil;
+
+public class Tomcat100PublishModuleVisitor extends TomcatPublishModuleVisitor {
+
+	/**
+	 * Instantiate a new Tomcat100PublishModuleVisitor
+	 * 
+	 * @param baseDir catalina base path
+	 * @param tomcatVersion tomcat version
+	 * @param serverInstance ServerInstance containing server.xml contents
+	 * @param sharedLoader string value for shared.loader catalina configuration property
+	 * @param enableMetaInfResources flag to indicate if Servlet 3.0 or greater "META-INF/resources" feature should be supported
+	 */
+	Tomcat100PublishModuleVisitor(IPath baseDir, String tomcatVersion, ServerInstance serverInstance, String sharedLoader, boolean enableMetaInfResources) {
+		super(baseDir, tomcatVersion, serverInstance, sharedLoader, enableMetaInfResources);
+	}
+
+    /**
+     * {@inheritDoc}
+     */
+	@Override
+    public void endVisitWebComponent(IVirtualComponent component)
+            throws CoreException {
+
+        // track context changes, don't rewrite if not needed
+        boolean dirty = false;
+
+        IModule module = ServerUtil.getModule(component.getProject());
+
+        // we need this for the user-specified context path
+        Context context = findContext(module);
+        if (context == null) {
+        	String name = module != null ? module.getName() : component.getName();
+    		Trace.trace(Trace.SEVERE, "Could not find context for module " + name);
+    		throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0,
+    				NLS.bind(Messages.errorPublishContextNotFound, name), null));
+        }
+
+		dirty = includeProjectContextXml(component, context);
+		dirty = updateDocBaseAndPath(component, context);
+
+		// Add WEB-INF/classes elements as PreResources
+		for (Iterator iterator = virtualClassClasspathElements.iterator();
+				iterator.hasNext();) {
+			Object virtualClassClasspathElement = iterator.next();
+			PreResources preResources = (PreResources)context.getResources().createElement("PreResources");
+			preResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+			preResources.setBase(virtualClassClasspathElement.toString());
+			preResources.setWebAppMount("/WEB-INF/classes");
+			preResources.setInternalPath("/");
+			preResources.setClassLoaderOnly("false");
+		}
+		virtualClassClasspathElements.clear();
+
+		// Add Jars as JarResources if a jar, or as PostResources if a utility project
+		for (Iterator iterator = virtualJarClasspathElements.iterator();
+				iterator.hasNext();) {
+			Object virtualJarClassClasspathElement = iterator.next();
+			String jarPath = virtualJarClassClasspathElement.toString();
+			if (jarPath.endsWith(".jar")) {
+				JarResources jarResources = (JarResources)context.getResources().createElement("JarResources");
+				jarResources.setClassName("org.apache.catalina.webresources.JarResourceSet");
+				jarResources.setBase(jarPath);
+				jarResources.setWebAppMount("/WEB-INF/classes");
+				jarResources.setInternalPath("/");
+				jarResources.setClassLoaderOnly("true");
+			}
+			else {
+				PostResources postResources = (PostResources)context.getResources().createElement("PostResources");
+				postResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+				postResources.setBase(jarPath);
+				postResources.setWebAppMount("/WEB-INF/classes");
+				postResources.setInternalPath("/");
+				postResources.setClassLoaderOnly("false");
+				// Map META-INF tld files to WEB-INF
+				File metaInfDir = new File(jarPath + "/META-INF");
+				if (metaInfDir.isDirectory() && metaInfDir.exists()) {
+					// Map META-INF directory directly to /META-INF
+					postResources = (PostResources)context.getResources().createElement("PostResources");
+					postResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+					postResources.setBase(metaInfDir.getPath());
+					postResources.setWebAppMount("/META-INF");
+					postResources.setInternalPath("/");
+					postResources.setClassLoaderOnly("false");
+
+					File [] tldFiles = metaInfDir.listFiles(new FileFilter() {
+							public boolean accept(File file) {
+								if (file.isFile() && file.getName().endsWith(".tld")) {
+									return true;
+								}
+								return false;
+							}
+						});
+					for (int i = 0; i < tldFiles.length; i++) {
+						postResources = (PostResources)context.getResources().createElement("PostResources");
+						postResources.setClassName("org.apache.catalina.webresources.FileResourceSet");
+						postResources.setBase(tldFiles[0].getPath());
+						postResources.setWebAppMount("/WEB-INF/" + tldFiles[0].getName());
+						postResources.setInternalPath("/");
+						postResources.setClassLoaderOnly("false");
+					}
+				}
+			}
+		}
+		virtualJarClasspathElements.clear();
+
+		Set<String> rtPathsProcessed = new HashSet<String>();
+		Set<String> locationsIncluded = new HashSet<String>();
+		String docBase = context.getDocBase();
+		locationsIncluded.add(docBase);
+		Map<String, String> retryLocations = new HashMap<String, String>();
+		IVirtualResource [] virtualResources = component.getRootFolder().getResources("");
+		// Loop over the module's resources
+		for (int i = 0; i < virtualResources.length; i++) {
+			String rtPath = virtualResources[i].getRuntimePath().toString();
+			// Note: The virtual resources returned only know their runtime path.
+			// Asking for the project path for this resource performs a lookup
+			// that will only return the path for the first mapping for the
+			// runtime path.  Thus use of getUnderlyingResources() is necessary.
+			// However, this returns matching resources from all mappings so
+			// we have to try to keep only those that are mapped directly
+			// to the runtime path in the .components file.
+
+			// If this runtime path has not yet been processed
+			if (!rtPathsProcessed.contains(rtPath)) {
+				// If not a Java related resource
+				if (!"/WEB-INF/classes".equals(rtPath)) {
+					// Get all resources for this runtime path
+					IResource[] underlyingResources = virtualResources[i].getUnderlyingResources();
+					// If resource is mapped to "/", then we know it corresponds directly
+					// to a mapping in the .components file
+					if ("/".equals(rtPath)) {
+						for (int j = 0; j < underlyingResources.length; j++) {
+							IPath resLoc = underlyingResources[j].getLocation();
+							String location = resLoc.toOSString();
+							if (!location.equals(docBase)) {
+								PreResources preResources = (PreResources)context.getResources().createElement("PreResources");
+								preResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+								preResources.setBase(location);
+								preResources.setWebAppMount("/");
+								preResources.setInternalPath("/");
+								preResources.setClassLoaderOnly("false");
+								// Add to the set of locations included
+								locationsIncluded.add(location);
+							}
+						}
+					}
+					// Else this runtime path is something other than "/"
+					else {
+						int idx = rtPath.lastIndexOf('/');
+						// If a "normal" runtime path
+						if (idx >= 0) {
+							// Get the name of the last segment in the runtime path
+							String lastSegment = rtPath.substring(idx + 1);
+							// Check the underlying resources to determine which correspond to mappings
+							for (int j = 0; j < underlyingResources.length; j++) {
+								IPath resLoc = underlyingResources[j].getLocation();
+								String location = resLoc.toOSString();
+								// If the last segment of the runtime path doesn't match the
+								// the last segment of the location, then we have a direct mapping
+								// from the .contents file.
+								if (!lastSegment.equals(resLoc.lastSegment())) {
+									PreResources preResources = (PreResources)context.getResources().createElement("PreResources");
+									preResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+									preResources.setBase(location);
+									preResources.setWebAppMount(rtPath);
+									preResources.setInternalPath("/");
+									preResources.setClassLoaderOnly("false");
+									// Add to the set of locations included
+									locationsIncluded.add(location);
+								}
+								// Else last segment of runtime path did match the last segment
+								// of the location.  We likely have a subfolder of a mapping
+								// that matches a portion of the runtime path.
+								else {
+									// Since we can't be sure, save so it can be check again later
+									retryLocations.put(location, rtPath);
+								}
+							}
+						}
+					}
+				}
+				// Add the runtime path to those already processed
+				rtPathsProcessed.add(rtPath);
+			}
+		}
+		// If there are locations to retry, add any not yet included in extra paths setting
+		if (!retryLocations.isEmpty()) {
+			// Remove retry locations already included in the extra paths
+			for (Iterator iterator = retryLocations.keySet().iterator(); iterator.hasNext();) {
+				String location = (String)iterator.next();
+				for (Iterator iterator2 = locationsIncluded.iterator(); iterator2.hasNext();) {
+					String includedLocation = (String)iterator2.next();
+					if (location.equals(includedLocation) || location.startsWith(includedLocation + File.separator)) {
+						iterator.remove();
+						break;
+					}
+				}
+			}
+			// If any entries are left, include them in the extra paths
+			if (!retryLocations.isEmpty()) {
+				for (Iterator iterator = retryLocations.entrySet().iterator(); iterator.hasNext();) {
+					Map.Entry entry = (Map.Entry)iterator.next();
+					String location = (String)entry.getKey();
+					String rtPath = (String)entry.getValue();
+					PreResources preResources = (PreResources)context.getResources().createElement("PreResources");
+					preResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+					preResources.setBase(location);
+					preResources.setWebAppMount(rtPath);
+					preResources.setInternalPath("/");
+					preResources.setClassLoaderOnly("false");
+				}
+			}
+		}
+		if (!virtualDependentResources.isEmpty()) {
+			for (Map.Entry<String, List<String>> entry : virtualDependentResources.entrySet()) {
+				String rtPath = entry.getKey();
+				List<String> locations = entry.getValue();
+				for (String location : locations) {
+					PostResources postResources = (PostResources)context.getResources().createElement("PostResources");
+					postResources.setClassName("org.apache.catalina.webresources.DirResourceSet");
+					postResources.setBase(location);
+					postResources.setWebAppMount(rtPath.length() > 0 ? rtPath : "/");
+					postResources.setInternalPath("/");
+					postResources.setClassLoaderOnly("false");
+				}
+			}
+		}
+		virtualDependentResources.clear();
+
+		if (dirty) {
+			//TODO If writing to separate context XML files, save "dirty" status for later use
+		}
+	}
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPlugin.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPlugin.java
index 71119b6..4a81504 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPlugin.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPlugin.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2016 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -46,6 +46,7 @@
 	public static final String TOMCAT_80 = "org.eclipse.jst.server.tomcat.80";
 	public static final String TOMCAT_85 = "org.eclipse.jst.server.tomcat.85";
 	public static final String TOMCAT_90 = "org.eclipse.jst.server.tomcat.90";
+	public static final String TOMCAT_100 = "org.eclipse.jst.server.tomcat.100";
 
 	// Beyond 8.0, this verification approach is not effective and actually isn't currently used for 7.0 and beyond (see verifyInstallPath method).
 	protected static final String VERIFY_INSTALL_FILE = "verifyInstall.properties";
@@ -164,6 +165,8 @@
 			return new Tomcat85Handler();
 		else if (TOMCAT_90.equals(id))
 			return new Tomcat90Handler();
+		else if (TOMCAT_100.equals(id))
+			return new Tomcat100Handler();
 		else
 			return null;
 	}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntime.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntime.java
index 056b647..fe507cc 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntime.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntime.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2017 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -142,7 +142,7 @@
 		String id = getRuntime().getRuntimeType().getId();
 		if (!found) {
 			if (id != null && (id.indexOf("55") > 0 || id.indexOf("60") > 0 || id.indexOf("70") > 0 || id.indexOf("80") > 0
-					|| id.indexOf("85") > 0 || id.indexOf("90") > 0)) {
+					|| id.indexOf("85") > 0 || id.indexOf("90") > 0 || id.indexOf("100") > 0)) {
 				found = true;
 			}
 		}
@@ -221,6 +221,17 @@
 			}
 		}
 
+		// Else for Tomcat 10.0, ensure we have J2SE 8.0
+		else if (id != null && id.indexOf("100") > 0) {
+			IVMInstall vmInstall = getVMInstall();
+			if (vmInstall instanceof IVMInstall2) {
+				String javaVersion = ((IVMInstall2)vmInstall).getJavaVersion();
+				if (javaVersion != null && !isVMMinimumVersion(javaVersion, 108)) {
+					return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorJRETomcat100, null);
+				}
+			}
+		}
+
 		return Status.OK_STATUS;
 	}
 
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeClasspathProvider.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeClasspathProvider.java
index d8ff94d..4d8256b 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeClasspathProvider.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeClasspathProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2018 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -33,14 +33,16 @@
 	private static final String JST_WEB_FACET_ID = "jst.web";
 
 	private final String getEEJavadocLocation(IProject project) {
-		int eeVersion = 8;
+		int eeVersion = 9;
 		try {
 			IFacetedProject faceted = ProjectFacetsManager.create(project);
 			if (faceted != null && ProjectFacetsManager.isProjectFacetDefined(JST_WEB_FACET_ID)) {
 				IProjectFacet webModuleFacet = ProjectFacetsManager.getProjectFacet(JST_WEB_FACET_ID);
 				if (faceted.hasProjectFacet(webModuleFacet)) {
 					String servletVersionStr = faceted.getInstalledVersion(webModuleFacet).getVersionString();
-					if (servletVersionStr.equals("4.0")) {
+					if (servletVersionStr.equals("5.0")) {
+						eeVersion = 9;
+					} else if (servletVersionStr.equals("4.0")) {
 						eeVersion = 8;
 					} else if (servletVersionStr.equals("3.1")) {
 						eeVersion = 7;
@@ -63,7 +65,7 @@
 			// default to the latest
 		}
 
-		String url = "https://javaee.github.io/javaee-spec/javadocs/";
+		String url = "https://jakarta.ee/specifications/servlet/5.0/apidocs/";
 		switch (eeVersion) {
 		case 3:
 			url = "https://docs.oracle.com/javaee/3/api/";
@@ -84,7 +86,8 @@
 			url = "https://javaee.github.io/javaee-spec/javadocs/";
 			break;
 		default:
-			url = "https://javaee.github.io/javaee-spec/javadocs/";
+			// Servlet Javadoc. Jakarta EE 9 doesn't appear to have a central URL for all Javadoc.
+			url = "https://jakarta.ee/specifications/servlet/5.0/apidocs/";
 			break;
 		}
 
@@ -92,9 +95,12 @@
 	}
 
 	private String getTomcatJavadocLocation(IRuntime runtime) {
-		/* Default to v9.0 doc. v7.0 is currently the oldest advertised version on the front page */
-		String tomcatDocURL = "https://tomcat.apache.org/tomcat-9.0-doc/api/";
+		/* Default to v10.0 doc. v7.0 is currently the oldest advertised version on the front page */
+		String tomcatDocURL = "http://tomcat.apache.org/tomcat-10.0-doc/api/";
 		String runtimeTypeId = runtime.getRuntimeType().getId();
+		if (runtimeTypeId.indexOf("90") > 0) {
+			tomcatDocURL = "https://tomcat.apache.org/tomcat-9.0-doc/api/";
+		}
 		if (runtimeTypeId.indexOf("85") > 0) {
 			tomcatDocURL = "https://tomcat.apache.org/tomcat-8.5-doc/api/";
 		}
@@ -120,7 +126,7 @@
 		if (runtimeId.indexOf("32") > 0) {
 			IPath path = installPath.append("lib");
 			addLibraryEntries(list, path.toFile(), true);
-		} else if (runtimeId.indexOf("60") > 0 || runtimeId.indexOf("70") > 0 || runtimeId.indexOf("80") > 0 || runtimeId.indexOf("85") > 0 || runtimeId.indexOf("90") > 0) {
+		} else if (runtimeId.indexOf("60") > 0 || runtimeId.indexOf("70") > 0 || runtimeId.indexOf("80") > 0 || runtimeId.indexOf("85") > 0 || runtimeId.indexOf("90") > 0 || runtimeId.indexOf("100") > 0) {
 			// TODO May need some flexibility in case the installation has been configured differently
 			// This lib "simplification" may cause issues for some.
 			// Not known yet whether packaged Linux installs will go along.
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeLocator.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeLocator.java
index 99729a3..8c8883d 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeLocator.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatRuntimeLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2016 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -36,7 +36,8 @@
 		"org.eclipse.jst.server.tomcat.runtime.70",
 		"org.eclipse.jst.server.tomcat.runtime.80",
 		"org.eclipse.jst.server.tomcat.runtime.85",
-		"org.eclipse.jst.server.tomcat.runtime.90"};
+		"org.eclipse.jst.server.tomcat.runtime.90",
+		"org.eclipse.jst.server.tomcat.runtime.100"};
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.wst.server.core.model.IRuntimeFactoryDelegate#getKnownRuntimes()
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServer.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServer.java
index 0962dec..a5640bf 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServer.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatServer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2016 IBM Corporation and others.
+ * Copyright (c) 2003, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -124,6 +124,8 @@
 					tcConfig = new Tomcat85Configuration(folder);
 				else if (id.indexOf("90") > 0)
 					tcConfig = new Tomcat90Configuration(folder);
+				else if (id.indexOf("100") > 0)
+					tcConfig = new Tomcat100Configuration(folder);
 				else {
 					throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorUnknownVersion, null));
 				}
@@ -181,6 +183,8 @@
 			tcConfig = new Tomcat85Configuration(folder);
 		else if (id.indexOf("90") > 0)
 			tcConfig = new Tomcat90Configuration(folder);
+		else if (id.indexOf("100") > 0)
+			tcConfig = new Tomcat100Configuration(folder);
 		else {
 			throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorUnknownVersion, null));
 		}
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 7cfe414..d9dae2b 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
@@ -1,5 +1,5 @@
 /**********************************************************************
- * Copyright (c) 2007, 2017 SAS Institute, Inc and others.
+ * Copyright (c) 2007, 2020 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 2.0
  * which accompanies this distribution, and is available at
@@ -111,6 +111,7 @@
 		versionStringMap.put(TomcatPlugin.TOMCAT_80, "8.0.");
 		versionStringMap.put(TomcatPlugin.TOMCAT_85, "8.5.");
 		versionStringMap.put(TomcatPlugin.TOMCAT_90, "9.0.");
+		versionStringMap.put(TomcatPlugin.TOMCAT_100, "10.0.");
 	}
 
 	/**
@@ -923,6 +924,7 @@
 			boolean isTomcat80 = tomcatVersion.startsWith("8.0");
 			boolean isTomcat85 = tomcatVersion.startsWith("8.5");
 			boolean isTomcat9 = tomcatVersion.startsWith("9.");
+			boolean isTomcat10 = tomcatVersion.startsWith("10.");
 			// care about top-level modules only
 			TomcatPublishModuleVisitor visitor;
 			if (isTomcat80) {
@@ -937,6 +939,10 @@
 				visitor = new Tomcat90PublishModuleVisitor(
 						baseDir, tomcatVersion, publishedInstance, loader, enableMetaInfResources);
 			}
+			else if (isTomcat10) {
+				visitor = new Tomcat100PublishModuleVisitor(
+						baseDir, tomcatVersion, publishedInstance, loader, enableMetaInfResources);
+			}
 			else {
 				visitor = new TomcatPublishModuleVisitor(
 						baseDir, tomcatVersion, publishedInstance, loader, enableMetaInfResources);
@@ -1150,7 +1156,7 @@
 		File jarFile = null;
 		
 		if (TomcatPlugin.TOMCAT_60.equals(serverType) || TomcatPlugin.TOMCAT_70.equals(serverType) || TomcatPlugin.TOMCAT_80.equals(serverType)
-				|| TomcatPlugin.TOMCAT_85.equals(serverType) || TomcatPlugin.TOMCAT_90.equals(serverType)) {
+				|| TomcatPlugin.TOMCAT_85.equals(serverType) || TomcatPlugin.TOMCAT_90.equals(serverType) || TomcatPlugin.TOMCAT_100.equals(serverType)) {
 			catalinaJarPath = installPath.append("lib").append("catalina.jar");
 			jarFile = catalinaJarPath.toFile();
 			// If jar is not at expected location, try alternate location
diff --git a/plugins/org.eclipse.jst.server.tomcat.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.jst.server.tomcat.ui/META-INF/MANIFEST.MF
index a7521e7..a9bb217 100644
--- a/plugins/org.eclipse.jst.server.tomcat.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.jst.server.tomcat.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jst.server.tomcat.ui; singleton:=true
-Bundle-Version: 1.1.800.qualifier
+Bundle-Version: 1.1.900.qualifier
 Bundle-Activator: org.eclipse.jst.server.tomcat.ui.internal.TomcatUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.jst.server.tomcat.ui/plugin.xml b/plugins/org.eclipse.jst.server.tomcat.ui/plugin.xml
index f411f64..e18386b 100644
--- a/plugins/org.eclipse.jst.server.tomcat.ui/plugin.xml
+++ b/plugins/org.eclipse.jst.server.tomcat.ui/plugin.xml
@@ -43,6 +43,10 @@
          id="org.eclipse.jst.server.tomcat.90"
          icon="icons/obj16/tomcat.gif"
          typeIds="org.eclipse.jst.server.tomcat.runtime.90"/>
+      <image
+         id="org.eclipse.jst.server.tomcat.100"
+         icon="icons/obj16/tomcat.gif"
+         typeIds="org.eclipse.jst.server.tomcat.runtime.100"/>
 
       <image
          id="org.eclipse.jst.server.tomcat.32"
@@ -84,6 +88,10 @@
          id="org.eclipse.jst.server.tomcat.90"
          icon="icons/obj16/tomcat.gif"
          typeIds="org.eclipse.jst.server.tomcat.90"/>
+      <image
+         id="org.eclipse.jst.server.tomcat.100"
+         icon="icons/obj16/tomcat.gif"
+         typeIds="org.eclipse.jst.server.tomcat.100"/>
    </extension>
    
    <extension point="org.eclipse.core.expressions.propertyTesters">
@@ -185,6 +193,10 @@
          id="org.eclipse.jst.server.tomcat.runtime.90"
          typeIds="org.eclipse.jst.server.tomcat.runtime.90"
          class="org.eclipse.jst.server.tomcat.ui.internal.TomcatRuntimeWizardFragment"/>
+      <fragment
+         id="org.eclipse.jst.server.tomcat.runtime.100"
+         typeIds="org.eclipse.jst.server.tomcat.runtime.100"
+         class="org.eclipse.jst.server.tomcat.ui.internal.TomcatRuntimeWizardFragment"/>
    </extension>
 
   <extension point="org.eclipse.debug.ui.launchConfigurationTypeImages">
diff --git a/plugins/org.eclipse.jst.server.tomcat.ui/pom.xml b/plugins/org.eclipse.jst.server.tomcat.ui/pom.xml
index 3081460..41ff9f7 100644
--- a/plugins/org.eclipse.jst.server.tomcat.ui/pom.xml
+++ b/plugins/org.eclipse.jst.server.tomcat.ui/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!--

-  Copyright (c) 2012, 2016 Eclipse Foundation and others.

+  Copyright (c) 2012, 2020 Eclipse Foundation and others.

   All rights reserved. This program and the accompanying materials

   are made available under the terms of the Eclipse Distribution License v1.0

   which accompanies this distribution, and is available at

@@ -8,7 +8,7 @@
  

   Contributors:

     Thanh Ha (Eclipse Foundation) - initial implementation

--->
+-->

 

 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

@@ -22,6 +22,6 @@
 

   <groupId>org.eclipse.webtools.servertools</groupId>

   <artifactId>org.eclipse.jst.server.tomcat.ui</artifactId>

-  <version>1.1.800-SNAPSHOT</version>

+  <version>1.1.900-SNAPSHOT</version>

   <packaging>eclipse-plugin</packaging>

 </project>