[124914] Implement main portion of experimental Tomcat plug-in to serve modules without publishing.  Does not save contexts to separate XML files.  The "loader" jars are also simple Java projects that can be rebuilt by specifying a classpath variable that points to an appropriate Tomcat installation,
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 8cd9b0f..aea71e2 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
@@ -19,6 +19,9 @@
  org.eclipse.jdt.launching;bundle-version="[3.2.0,4.0.0)",
  org.eclipse.wst.server.core;bundle-version="[1.0.204,1.1.0)",
  org.eclipse.jst.server.core;bundle-version="[1.0.103,1.1.0)",
- org.eclipse.jst.common.project.facet.core;bundle-version="[1.1.0,1.2.0)"
+ org.eclipse.jst.common.project.facet.core;bundle-version="[1.1.0,1.2.0)",
+ org.eclipse.wst.common.modulecore;bundle-version="[1.1.0,1.2.0)",
+ org.eclipse.jst.j2ee;bundle-version="[1.1.0,1.2.0)",
+ org.eclipse.emf.common
 Eclipse-LazyStart: true
 Bundle-RequiredExecutionEnvironment: J2SE-1.4
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.50.loader.jar b/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.50.loader.jar
new file mode 100644
index 0000000..6a4a4d3
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.50.loader.jar
Binary files differ
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.55.loader.jar b/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.55.loader.jar
new file mode 100644
index 0000000..17f0382
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.55.loader.jar
Binary files differ
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.60.loader.jar b/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.60.loader.jar
new file mode 100644
index 0000000..72f19e0
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/org.eclipse.jst.server.tomcat.runtime.60.loader.jar
Binary files differ
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/CatalinaPropertiesUtil.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/CatalinaPropertiesUtil.java
new file mode 100644
index 0000000..9876742
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/CatalinaPropertiesUtil.java
@@ -0,0 +1,136 @@
+/**********************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Igor Fedorenko & Fabrizio Giustina - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Utility methods for handling loaders in catalina.properties.
+ */
+public class CatalinaPropertiesUtil {
+
+    /**
+     * Don't instantiate
+     */
+    private CatalinaPropertiesUtil() {
+        // unused
+    }
+
+    /**
+     * Adds a list of path elements to a specific loader in catalina.properties.
+     * This method doesn't use java.util.Properties in order to keep file
+     * formatting intact.
+     * 
+     * @param file catalina.properties file
+     * @param loader loader name
+     * @param elements List of classpath elements
+     * @throws IOException
+     */
+    public static void addGlobalClasspath(File file, String loader,
+            String[] elements) throws IOException {
+
+        String propertyName = loader + ".loader";
+
+        BufferedReader br = null;
+        StringBuffer buffer = new StringBuffer();
+        boolean added = false;
+
+        try {
+            br = new BufferedReader(new FileReader(file));
+            String line = br.readLine();
+            while (line != null) {
+
+                if (line.startsWith(propertyName)) {
+                    added = true;
+                    line = addElements(line, elements);
+                }
+
+                buffer.append(line);
+                buffer.append("\n");
+                line = br.readLine();
+            }
+        } finally {
+            if (br != null) {
+                br.close();
+            }
+        }
+        if (!added) {
+            // should never happen with an original catalina.properties,
+            // but better handle also files modified by users
+            buffer.append(propertyName);
+            buffer.append("=");
+            for (int i = 0; i < elements.length; i++) {
+                buffer.append(elements[i]);
+            }
+            buffer.append("\n");
+        }
+
+        String propertyFile = buffer.toString();
+
+        BufferedWriter bw = null;
+        try {
+            bw = new BufferedWriter(new FileWriter(file));
+            bw.write(propertyFile);
+        } finally {
+            if (br != null) {
+                bw.close();
+            }
+        }
+    }
+
+    /**
+     * Append a list of path to the property at the given line and returns the
+     * modified name.
+     * @param line line (property=value)
+     * @param elements classpath elements to add.
+     * @return modified line
+     */
+    private static String addElements(String line, String[] elements) {
+        String[] propAndValue = line.split("=");
+        String loaderProperty = "";
+
+        if (propAndValue.length > 1) {
+            loaderProperty = propAndValue[1];
+        }
+
+        Set classpath = new LinkedHashSet();
+
+        StringTokenizer st = new StringTokenizer(loaderProperty, ",");
+        while (st.hasMoreTokens()) {
+            classpath.add(st.nextToken());
+        }
+
+        for (int i = 0; i < elements.length; i++) {
+            classpath.add(elements[i]);
+        }
+
+        StringBuffer sb = new StringBuffer();
+        sb.append(propAndValue[0]);
+        sb.append("=");
+        for (Iterator it = classpath.iterator(); it.hasNext();) {
+            sb.append(it.next());
+            if (it.hasNext()) {
+                sb.append(',');
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServer.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServer.java
index eee5098..4e09d34 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServer.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServer.java
@@ -1,5 +1,5 @@
 /**********************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2006, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -34,6 +34,12 @@
 	public static final String PROPERTY_DEPLOY_DIR = "deployDir";
 
 	/**
+	 * Property which specifies if modules should be served without
+	 * publishing.
+	 */
+	public static final String PROPERTY_SERVE_MODULES_WITHOUT_PUBLISH = "serveModulesWithoutPublish";
+
+	/**
 	 * Returns true if this is a test (publish and run code out of the
 	 * workbench) environment server.
 	 *
@@ -58,4 +64,12 @@
 	 * @return directory where web applications are deployed
 	 */
 	public String getDeployDirectory();
+	
+	/**
+	 * Returns true if modules should be served directly from the project
+	 * folders without publishing.
+	 * 
+	 * @return true if modules should not be published but served directly
+	 */
+	public boolean isServeModulesWithoutPublish();
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServerWorkingCopy.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServerWorkingCopy.java
index 75e169b..b6dc882 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServerWorkingCopy.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatServerWorkingCopy.java
@@ -47,4 +47,11 @@
 	 * @param deployDir deployment directory for the server
 	 */
 	public void setDeployDirectory(String deployDir);
+	
+	/**
+	 * Set this server to serve modules without publishing.
+	 * 
+	 * @param b true if modules should be served without publishing
+	 */
+	public void setServeModulesWithoutPublish(boolean b);
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatVersionHandler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatVersionHandler.java
index fc3b107..9cea32d 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatVersionHandler.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/ITomcatVersionHandler.java
@@ -100,7 +100,7 @@
 	 * 
 	 * @param server TomcatServer instance from which to determine
 	 * the base path.
-	 * @return the server base path
+	 * @return path to Tomcat instance directory
 	 */
 	public IPath getRuntimeBaseDirectory(TomcatServer server);
 
@@ -108,7 +108,7 @@
 	 * Prepare server runtime directory. Create catalina instance set of
 	 * directories.
 	 * 
-	 * @param baseDir directory at which to prepare the runtime directory.
+	 * @param baseDir Tomcat instance directory to prepare
 	 * @return result of creation operation 
 	 */
 	public IStatus prepareRuntimeDirectory(IPath baseDir);
@@ -118,7 +118,47 @@
 	 * initialized appropriately.
 	 * 
 	 * @param deployPath path to the deployment directory
+	 *  being prepared
 	 * @return status result of the operation
 	 */
 	public IStatus prepareDeployDirectory(IPath deployPath);
+	
+	/**
+	 * Prepare directory for serving contexts directly if enabled.
+	 * If not enabled, restore directory if necessary.
+	 * 
+	 * @param baseDir path to Tomcat instance directory
+	 * @param server TomcatServer instance from which to determine
+	 * if serving directly is enabled
+	 * @return status result of the operation
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server);
+	
+	/**
+	 * Gets the name of the "shared" loader to use with serving
+	 * modules without publishing.  Returns null if serving modules
+	 * without publishing is not supported.
+	 * 
+	 * @param baseDir path to Tomcat instance directory
+	 * @return name of shared loader
+	 */
+	public String getSharedLoader(IPath baseDir);
+	
+	/**
+	 * Returns true if this server supports serving modules without
+	 * publishing.
+	 * 
+	 * @return true if serving modules without publishing is supported
+	 */
+	public boolean supportsServeModulesWithoutPublish();
+	
+	/**
+	 * Returns true if this server supports a debug argument. This
+	 * argument is expected to affect the level of logging.  Newer
+	 * versions of Tomcat use different means of controlling logging
+	 * and ignore this argument.
+	 * 
+	 * @return true if debug argument is supported
+	 */
+	public boolean supportsDebugArgument();
 }
\ No newline at end of file
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 d2155b8..732211f 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 IBM Corporation and others.
+ * Copyright (c) 2005, 2006, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -83,6 +83,13 @@
 	public static String errorXMLContextNotFoundPath;
 	public static String errorXMLContextMangerNotFound;
 	public static String errorXMLContextNotFoundPath32;
+	public static String errorNoPublishNotSupported;
+	public static String errorPublishContextNotFound;
+	public static String errorPublishCouldNotRemoveModule;
+	public static String errorPublishLoaderJarNotFound;
+	public static String errorPublishURLConvert;
+	public static String errorPublishCantDeleteLoaderJar;
+	public static String errorPublishCatalinaProps;
 
 	public static String configurationEditorActionModifyPort;
 	public static String configurationEditorActionModifyMimeMapping;
@@ -96,6 +103,7 @@
 	public static String serverEditorActionSetSecure;
 	public static String serverEditorActionSetServerDirectory;
 	public static String serverEditorActionSetDeployDirectory;
+	public static String serverEditorActionSetServeWithoutPublish;
 	public static String fixModuleContextRootDescription;
 	public static String fixModuleContextRoot;
 
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 305e01c..407bc59 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, 2005 IBM Corporation and others.
+# Copyright (c) 2004, 2005, 2006, 2007 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -100,6 +100,13 @@
 errorXMLContextNotFoundPath=Context with path \"{0}\" was not found under Service \"{1}\", Engine \"{2}\", and Host \"{3}\".
 errorXMLContextMangerNotFound=ContextManager element was not found.
 errorXMLContextNotFoundPath32=Context with path \"{0}\" was not found under ContextManager.
+errorNoPublishNotSupported=Serving modules without publishing is not supported by this server.
+errorPublishContextNotFound=Context not found for module {0}.
+errorPublishCouldNotRemoveModule=Could not remove module {0}.
+errorPublishLoaderJarNotFound=Loader jar not found for server ID: {0}.
+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}.
 
 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.
@@ -109,3 +116,4 @@
 serverEditorActionSetDebugMode=Tomcat Debug Option Change
 serverEditorActionSetServerDirectory=Tomcat Server Path Change
 serverEditorActionSetDeployDirectory=Tomcat Deploy Path Change
+serverEditorActionSetServeWithoutPublish=Serve Modules Without Publish Change
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/PublishOperation2.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/PublishOperation2.java
index 3b285a7..613109e 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/PublishOperation2.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/PublishOperation2.java
@@ -28,6 +28,15 @@
 	protected int kind;
 	protected int deltaKind;
 
+	/**
+	 * Construct the operation object to publish the specified module
+	 * to the specified server.
+	 * 
+	 * @param server server to which the module will be published
+	 * @param kind kind of publish
+	 * @param module module to publish
+	 * @param deltaKind kind of change
+	 */
 	public PublishOperation2(TomcatServerBehaviour server, int kind, IModule[] module, int deltaKind) {
 		super("Publish to server", "Publish Web module to Tomcat server");
 		this.server = server;
@@ -36,14 +45,23 @@
 		this.deltaKind = deltaKind;
 	}
 
+	/**
+	 * @see PublishOperation#getOrder()
+	 */
 	public int getOrder() {
 		return 0;
 	}
 
+	/**
+	 * @see PublishOperation#getKind()
+	 */
 	public int getKind() {
 		return REQUIRED;
 	}
 
+	/**
+	 * @see PublishOperation#execute(IProgressMonitor, IAdaptable)
+	 */
 	public void execute(IProgressMonitor monitor, IAdaptable info) throws CoreException {
 		List status = new ArrayList();
 		if (module.length == 1) { // web module
@@ -58,14 +76,17 @@
 	private void publishDir(IModule module2, List status, IProgressMonitor monitor) throws CoreException {
 		IPath path = server.getModuleDeployDirectory(module2);
 		
-		if (kind == IServer.PUBLISH_CLEAN || deltaKind == ServerBehaviourDelegate.REMOVED) { // clean and republish from scratch
+		// Remove if requested or if previously published and are now serving without publishing
+		if (kind == IServer.PUBLISH_CLEAN || deltaKind == ServerBehaviourDelegate.REMOVED
+				|| server.getTomcatServer().isServeModulesWithoutPublish()) {
 			File f = path.toFile();
 			if (f.exists()) {
 				IStatus[] stat = PublishUtil.deleteDirectory(f, monitor);
 				addArrayToList(status, stat);
 			}
 			
-			if (deltaKind == ServerBehaviourDelegate.REMOVED)
+			if (deltaKind == ServerBehaviourDelegate.REMOVED
+					|| server.getTomcatServer().isServeModulesWithoutPublish())
 				return;
 		}
 		
@@ -90,11 +111,14 @@
 		path = path.append("WEB-INF").append("lib");
 		IPath jarPath = path.append(module[1].getName() + ".jar");
 		
-		if (kind == IServer.PUBLISH_CLEAN || deltaKind == ServerBehaviourDelegate.REMOVED) { // clean and republish from scratch
+		// Remove if requested or if previously published and are now serving without publishing
+		if (kind == IServer.PUBLISH_CLEAN || deltaKind == ServerBehaviourDelegate.REMOVED
+				|| server.getTomcatServer().isServeModulesWithoutPublish()) {
 			if (jarPath.toFile().exists())
 				jarPath.toFile().delete();
 			
-			if (deltaKind == ServerBehaviourDelegate.REMOVED)
+			if (deltaKind == ServerBehaviourDelegate.REMOVED
+					|| server.getTomcatServer().isServeModulesWithoutPublish())
 				return;
 		}
 		if (kind != IServer.PUBLISH_CLEAN && kind != IServer.PUBLISH_FULL) {
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Handler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Handler.java
index e74c049..2e0d348 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Handler.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat32Handler.java
@@ -88,7 +88,7 @@
 		List list = new ArrayList();
 		list.add("-Dtomcat.home=\"" + installPath.toOSString() + "\"");
 		// Include a system property for the configurable deploy location
-		list.add("-Dtomcat.deploy=\"" + deployPath.toOSString() + "\"");
+		list.add("-Dwtp.deploy=\"" + deployPath.toOSString() + "\"");
 		
 		String[] s = new String[list.size()];
 		list.toArray(s);
@@ -146,4 +146,37 @@
 		return TomcatVersionHelper.createDeploymentDirectory(deployPath,
 				TomcatVersionHelper.DEFAULT_WEBXML_SERVLET22);
 	}
+	
+	/**
+	 * @see ITomcatVersionHandler#prepareForServingDirectly(IPath, TomcatServer)
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server) {
+		if (server.isServeModulesWithoutPublish())
+			return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorNoPublishNotSupported, null);
+		return Status.OK_STATUS;
+	}
+	
+	/**
+	 * @see ITomcatVersionHandler#getSharedLoader(IPath)
+	 */
+	public String getSharedLoader(IPath baseDir) {
+		// Not supported
+		return null;
+	}
+	
+	/**
+	 * Returns false since Tomcat 3.2 doesn't support this feature.
+	 * 
+	 * @return false since feature is not supported
+	 */
+	public boolean supportsServeModulesWithoutPublish() {
+		return false;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsDebugArgument()
+	 */
+	public boolean supportsDebugArgument() {
+		return true;
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat40Handler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat40Handler.java
index 17ac0cb..36eed35 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat40Handler.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat40Handler.java
@@ -141,4 +141,37 @@
 		return TomcatVersionHelper.createDeploymentDirectory(deployPath,
 				TomcatVersionHelper.DEFAULT_WEBXML_SERVLET23);
 	}
+
+	/**
+	 * @see ITomcatVersionHandler#prepareForServingDirectly(IPath, TomcatServer)
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server) {
+		if (server.isServeModulesWithoutPublish())
+			return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorNoPublishNotSupported, null);
+		return Status.OK_STATUS;
+	}	
+	
+	/**
+	 * @see ITomcatVersionHandler#getSharedLoader(IPath)
+	 */
+	public String getSharedLoader(IPath baseDir) {
+		// Not supported
+		return null;
+	}
+	
+	/**
+	 * Returns false since Tomcat 4.0 doesn't support this feature.
+	 * 
+	 * @return false since feature is not supported
+	 */
+	public boolean supportsServeModulesWithoutPublish() {
+		return false;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsDebugArgument()
+	 */
+	public boolean supportsDebugArgument() {
+		return true;
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat41Handler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat41Handler.java
index cf5f4d6..8b9ad2d 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat41Handler.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat41Handler.java
@@ -127,4 +127,37 @@
 		return TomcatVersionHelper.createDeploymentDirectory(deployPath,
 				TomcatVersionHelper.DEFAULT_WEBXML_SERVLET23);
 	}
+	
+	/**
+	 * @see ITomcatVersionHandler#prepareForServingDirectly(IPath, TomcatServer)
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server) {
+		if (server.isServeModulesWithoutPublish())
+			return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, Messages.errorNoPublishNotSupported, null);
+		return Status.OK_STATUS;
+	}	
+	
+	/**
+	 * @see ITomcatVersionHandler#getSharedLoader(IPath)
+	 */
+	public String getSharedLoader(IPath baseDir) {
+		// Not supported
+		return null;
+	}
+	
+	/**
+	 * Returns false since Tomcat 4.1 doesn't support this feature.
+	 * 
+	 * @return false since feature is not supported
+	 */
+	public boolean supportsServeModulesWithoutPublish() {
+		return false;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsDebugArgument()
+	 */
+	public boolean supportsDebugArgument() {
+		return true;
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Configuration.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Configuration.java
index 6d608de..8385035 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Configuration.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Configuration.java
@@ -609,7 +609,19 @@
 	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 loader, IProgressMonitor monitor) {
+		return TomcatVersionHelper.updateContextsToServeDirectly(baseDir, loader, monitor);
+	}
+
 	/**
 	 * Cleanup the server instance.  This consists of deleting the work
 	 * directory associated with Contexts that are going away in the
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Handler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Handler.java
index d577ea5..fc60147 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Handler.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat50Handler.java
@@ -127,4 +127,54 @@
 		return TomcatVersionHelper.createDeploymentDirectory(deployPath,
 				TomcatVersionHelper.DEFAULT_WEBXML_SERVLET24);
 	}
+	
+	/**
+	 * @see ITomcatVersionHandler#prepareForServingDirectly(IPath, TomcatServer)
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server) {
+		IStatus status;
+		// If serving modules without publishing, loader jar is needed
+		if (server.isServeModulesWithoutPublish()) {
+			status = TomcatVersionHelper.copyLoaderJar(
+					getRuntimeBaseDirectory(server).append("server/lib"),
+					server.getServer().getRuntime().getRuntimeType().getId());
+			// If copy successful and running a separate server instance, modify catalina.properties
+			if (status.isOK() && server.isTestEnvironment()) {
+				status = TomcatVersionHelper.updatePropertiesToServeDirectly(baseDir, "server/lib", "server");
+			}
+		}
+		// Else ensure jar is removed
+		else {
+			TomcatVersionHelper.removeLoaderJar(
+					getRuntimeBaseDirectory(server).append("server/lib"),
+					server.getServer().getRuntime().getRuntimeType().getId());
+			// TODO Decide what to do with removal warning, maybe nothing
+			status = Status.OK_STATUS;
+		}
+		return status;
+	}
+	
+	/**
+	 * @see ITomcatVersionHandler#getSharedLoader(IPath)
+	 */
+	public String getSharedLoader(IPath baseDir) {
+		// Use shared loader
+		return "shared";
+	}
+	
+	/**
+	 * Returns true since Tomcat 5.x supports this feature.
+	 * 
+	 * @return true since feature is supported
+	 */
+	public boolean supportsServeModulesWithoutPublish() {
+		return true;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsDebugArgument()
+	 */
+	public boolean supportsDebugArgument() {
+		return false;
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat55Configuration.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat55Configuration.java
index c19938e..61d5433 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat55Configuration.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat55Configuration.java
@@ -607,6 +607,18 @@
 	}
 	
 	/**
+	 * 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 loader, IProgressMonitor monitor) {
+		return TomcatVersionHelper.updateContextsToServeDirectly(baseDir, loader, monitor);
+	}
+
+	/**
 	 * Cleanup the server instance.  This consists of deleting the work
 	 * directory associated with Contexts that are going away in the
 	 * up coming publish.
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Configuration.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Configuration.java
index 24fd5d4..2e07671 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Configuration.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Configuration.java
@@ -609,6 +609,18 @@
 	}
 	
 	/**
+	 * 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 loader, IProgressMonitor monitor) {
+		return TomcatVersionHelper.updateContextsToServeDirectly(baseDir, loader, monitor);
+	}
+
+	/**
 	 * Cleanup the server instance.  This consists of deleting the work
 	 * directory associated with Contexts that are going away in the
 	 * up coming publish.
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Handler.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Handler.java
index c6eefbf..7ac82a2 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Handler.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/Tomcat60Handler.java
@@ -121,4 +121,54 @@
 		return TomcatVersionHelper.createDeploymentDirectory(deployPath,
 				TomcatVersionHelper.DEFAULT_WEBXML_SERVLET25);
 	}
+
+	/**
+	 * @see ITomcatVersionHandler#prepareForServingDirectly(IPath, TomcatServer)
+	 */
+	public IStatus prepareForServingDirectly(IPath baseDir, TomcatServer server) {
+		IStatus status;
+		// If serving modules without publishing, loader jar is needed
+		// TODO Need to examine catalina.properties to ensure loader jar and catalina.properties are handled appropriately
+		if (server.isServeModulesWithoutPublish()) {
+			status = TomcatVersionHelper.copyLoaderJar(
+					getRuntimeBaseDirectory(server).append("lib"),
+					server.getServer().getRuntime().getRuntimeType().getId());
+			// If copy successful and running a separate server instance, modify catalina.properties
+			if (status.isOK() && server.isTestEnvironment()) {
+				status = TomcatVersionHelper.updatePropertiesToServeDirectly(baseDir, "lib", "common");
+			}
+		}
+		// Else ensure jar is removed
+		else {
+			TomcatVersionHelper.removeLoaderJar(
+					getRuntimeBaseDirectory(server).append("lib"),
+					server.getServer().getRuntime().getRuntimeType().getId());
+			// TODO Decide what to do with removal warning, maybe nothing
+			status = Status.OK_STATUS;
+		}
+		return status;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#getSharedLoader(IPath)
+	 */
+	public String getSharedLoader(IPath baseDir) {
+		return "common";
+	}
+	
+	/**
+	 * Returns true since Tomcat 6.x supports this feature.
+	 * 
+	 * @return true since feature is supported
+	 */
+	public boolean supportsServeModulesWithoutPublish() {
+		return true;
+	}
+
+	/**
+	 * @see ITomcatVersionHandler#supportsDebugArgument()
+	 */
+	public boolean supportsDebugArgument() {
+		return false;
+	}
 }
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatConfiguration.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatConfiguration.java
index ef9637c..15f636e 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatConfiguration.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatConfiguration.java
@@ -180,6 +180,11 @@
 	}
 
 	
+	protected IStatus updateContextsToServeDirectly(IPath baseDir, String loader, IProgressMonitor monitor) {
+		// Default implementation assumes nothing to do
+		return Status.OK_STATUS;
+	}
+	
 	protected IStatus cleanupServer(IPath confDir, IPath installDir, IProgressMonitor monitor) {
 		// Default implementation assumes nothing to clean
 		return Status.OK_STATUS;
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPublishModuleVisitor.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPublishModuleVisitor.java
new file mode 100644
index 0000000..3e5d360
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatPublishModuleVisitor.java
@@ -0,0 +1,331 @@
+/**********************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Igor Fedorenko & Fabrizio Giustina - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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.jdt.core.IClasspathEntry;
+import org.eclipse.jst.server.tomcat.core.internal.wst.IModuleVisitor;
+import org.eclipse.jst.server.tomcat.core.internal.xml.Factory;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Context;
+import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Loader;
+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.IVirtualFile;
+import org.eclipse.wst.server.core.IModule;
+import org.eclipse.wst.server.core.ServerUtil;
+
+/**
+ * Handles "publishing" for servers that can load classes and resources directly
+ * from the workspace. Instead of creating and deploying jars to the webapp this
+ * simply update the virtual classpath in the context xml file.
+ */
+public class TomcatPublishModuleVisitor implements IModuleVisitor {
+
+    /**
+     * Server base path (Catalina base).
+     */
+    protected final IPath baseDir;
+    
+    /**
+     * Server instance in which to modify the context
+     */
+    protected final ServerInstance serverInstance;
+
+    /**
+     * Catalina.properties loader to add global classpath entries
+     */
+    protected final String sharedLoader;
+    
+    /**
+     * Classpath entries added by ear configurations.
+     */
+    protected final List earCommonResources = new ArrayList();
+
+    /**
+     * List of classpath elements that will be used by the custom tomcat loader.
+     * This set should include any class dir from referenced project.
+     */
+    protected Set virtualClasspathElements = new LinkedHashSet();
+
+    /**
+     * Instantiate a new TomcatPublishModuleVisitor
+     * 
+     * @param catalinaBase catalina base path
+     * @param webModules list of
+     * <code>org.eclipse.jst.server.tomcat.core.internal.WebModule</code>
+     * configured for this server
+     */
+    TomcatPublishModuleVisitor(IPath catalinaBase, ServerInstance serverInstance, String sharedLoader) {
+        this.baseDir = catalinaBase;
+        this.serverInstance = serverInstance;
+        this.sharedLoader = sharedLoader;
+    }
+
+    /**
+     * @see IModuleVisitor#visitWebComponent(IVirtualComponent)
+     */
+    public void visitWebComponent(IVirtualComponent component)
+            throws CoreException {
+        // nothing to do, everything is done in endVisitWebComponent
+    }
+
+    /**
+     * @see IModuleVisitor#visitArchiveComponent(IPath, IPath)
+     */
+    public void visitArchiveComponent(IPath runtimePath, IPath workspacePath) {
+        addVirtualResource(runtimePath, workspacePath);
+    }
+
+    /**
+     * @see IModuleVisitor#visitDependentComponent(IPath, IPath)
+     */
+    public void visitDependentComponent(IPath runtimePath, IPath workspacePath) {
+        addVirtualResource(runtimePath, workspacePath);
+    }
+
+    /**
+     * @see IModuleVisitor#visitWebResource(IPath, IPath)
+     */
+    public void visitWebResource(IPath runtimePath, IPath workspacePath) {
+        addVirtualResource(runtimePath, workspacePath);
+    }
+
+    /**
+     * @see IModuleVisitor#visitEarResource(IPath, IPath)
+     */
+    public void visitEarResource(IPath runtimePath, IPath workspacePath) {
+        earCommonResources.add(workspacePath.toOSString());
+    }
+
+    /**
+     * @see IModuleVisitor#endVisitEarComponent(IVirtualComponent)
+     */
+    public void endVisitEarComponent(IVirtualComponent component)
+            throws CoreException {
+        if (earCommonResources.size() > 0) {
+            try {
+                CatalinaPropertiesUtil.addGlobalClasspath(baseDir.append(
+                		"conf/catalina.properties").toFile(), sharedLoader,
+                		(String[]) earCommonResources.toArray(new String[earCommonResources.size()]));
+            } catch (IOException e) {
+                Trace.trace(Trace.WARNING, "Unable to add ear path entries to catalina.properties", e);
+            } finally {
+                earCommonResources.clear();
+            }
+        }
+    }
+
+    /**
+     * @see IModuleVisitor#visitClasspathEntry(IPath, IClasspathEntry)
+     */
+    public void visitClasspathEntry(IPath rtFolder, IClasspathEntry entry) {
+        if (entry != null) {
+            addVirtualResource(rtFolder, entry.getPath());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    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));
+        }
+
+        String contextName = null;
+        boolean reloadable = true;
+
+        contextName = context.getPath();
+        reloadable = Boolean.valueOf(context.getReloadable()).booleanValue();
+
+        // now strip initial /
+        if (contextName.startsWith("/")) {
+            contextName = contextName.substring(1);
+        }
+
+        // root context is deployed with the "ROOT" name in tomcat
+        if ("".equals(contextName)) {
+            contextName = "ROOT";
+        }
+
+        // handle project context.xml
+        Context projectContext = getProjectContextXml(component);
+
+        if (projectContext != null) {
+            // copy configuration to server context
+            projectContext.copyChildrenTo(context);
+
+            Map attrs = projectContext.getAttributes();
+            Iterator iter = attrs.keySet().iterator();
+            while (iter.hasNext()) {
+                String name = (String) iter.next();
+                if (!name.equalsIgnoreCase("path")
+                        && !name.equalsIgnoreCase("docBase")
+                        && !name.equalsIgnoreCase("source")) {
+                    String value = (String) attrs.get(name);
+                    String actualValue = context.getAttributeValue(name);
+                    if (!value.equals(actualValue)) {
+                        context.setAttributeValue(name, value);
+                        dirty = true;
+                    }
+                }
+            }
+        }
+
+        // handle changes in docBase
+        String docBase = component.getRootFolder().getUnderlyingFolder()
+                .getLocation().toOSString();
+        if (!docBase.equals(context.getDocBase())) {
+            dirty = true;
+            context.setDocBase(docBase);
+        }
+
+        // handle changes in reloadable flag
+        if (reloadable != (Boolean.valueOf((context.getReloadable()))
+                .booleanValue())) {
+            dirty = true;
+            context.setReloadable(Boolean.toString(reloadable));
+        }
+
+        String path = (contextName.equals("ROOT") ? "" : "/" + contextName);
+        // handle changes in the path
+        // PATH is required for tomcat 5.0, but ignored in tomcat 5.5
+        if (!path.equals(context.getPath())) {
+            dirty = true;
+            context.setPath(path);
+        }
+
+        context.getResources().setClassName(
+                "org.eclipse.jst.server.tomcat.loader.WtpDirContext");
+
+        Loader loader = context.getLoader();
+
+        loader.setClassName("org.eclipse.jst.server.tomcat.loader.WtpWebappLoader");
+
+        // required for tomcat 5.5.20 due to the change in
+        // http://issues.apache.org/bugzilla/show_bug.cgi?id=39704
+        loader.setUseSystemClassLoaderAsParent(Boolean.FALSE.toString());
+
+        // write down the virtual classPath
+        StringBuffer buffer = new StringBuffer();
+        for (Iterator iterator = virtualClasspathElements.iterator(); iterator
+                .hasNext();) {
+            buffer.append(iterator.next());
+            if (iterator.hasNext()) {
+                buffer.append(";");
+            }
+        }
+        virtualClasspathElements.clear();
+
+        String vcp = buffer.toString();
+
+        String oldVcp = loader.getVirtualClasspath();
+
+        if (!vcp.equals(oldVcp)) {
+            // save only if needed
+            dirty = true;
+            loader.setVirtualClasspath(vcp);
+            context.getResources().setVirtualClasspath(vcp);
+        }
+
+        if (dirty) {
+        	//TODO If writing to separate context XML files, save "dirty" status for later use
+        }
+    }
+
+    private void addVirtualResource(IPath runtimePath, IPath workspacePath) {
+        virtualClasspathElements.add(workspacePath.toOSString());
+    }
+
+    /**
+     * Load a META-INF/context.xml file from project, if available
+     * 
+     * @param component web component containing the context.xml
+     * @return context element containing the context.xml
+     * @throws CoreException
+     */
+    protected Context getProjectContextXml(IVirtualComponent component)
+            throws CoreException {
+
+        // load or create module's context.xml document
+        IVirtualFile contextFile = (IVirtualFile) component.getRootFolder()
+                .findMember("META-INF/context.xml");
+
+        Context contextElement = null;
+
+        if (contextFile != null && contextFile.exists()) {
+
+            Factory factory = new Factory();
+            factory.setPackageName("org.eclipse.jst.server.tomcat.core.internal.xml.server40");
+
+            InputStream fis = null;
+            try {
+                fis = contextFile.getUnderlyingFile().getContents();
+                contextElement = (Context) factory.loadDocument(fis);
+            } catch (Exception e) {
+                Trace.trace(Trace.SEVERE, "Exception reading " + contextFile, e);
+            } finally {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+        return contextElement;
+    }
+
+    /**
+     * Returns the given module from the config.
+     * 
+     * @param module a web module
+     * @return a web module
+     */
+    protected Context findContext(IModule module) {
+        if (module == null) {
+            return null;
+        }
+
+        String source = module.getId();
+        
+        Context [] contexts = serverInstance.getContexts();
+        for (int i = 0; i < contexts.length; i++) {
+        	if (source.equals(contexts[i].getSource()))
+        		return contexts[i];
+		}
+        return null;
+    }
+}
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 3476538..6106f14 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
@@ -219,6 +219,18 @@
 		// Default to value used by prior WTP versions
 		return getAttribute(PROPERTY_DEPLOY_DIR, LEGACY_DEPLOYDIR);
 	}
+
+	/**
+	 * Returns true if modules should be served without publishing.
+	 * 
+	 * @return boolean
+	 */
+	public boolean isServeModulesWithoutPublish() {
+		// If feature is supported, return current setting
+		if (versionHandler.supportsServeModulesWithoutPublish())
+			return getAttribute(PROPERTY_SERVE_MODULES_WITHOUT_PUBLISH, false);
+		return false;
+	}
 	
 	/**
 	 * Gets the base directory where the server instance runs.  This
@@ -262,8 +274,10 @@
 		return buf.toString();
 	}
 
-	/*
+	/**
 	 * Returns the child module(s) of this module.
+	 * @param module module from which to get child module(s)
+	 * @return array of child module(s)
 	 */
 	public IModule[] getChildModules(IModule[] module) {
 		if (module == null)
@@ -283,8 +297,11 @@
 		return new IModule[0];
 	}
 
-	/*
+	/**
 	 * Returns the root module(s) of this module.
+	 * @param module module from which to get the root module
+	 * @return root module
+	 * @throws CoreException 
 	 */
 	public IModule[] getRootModules(IModule module) throws CoreException {
 		if ("jst.web".equals(module.getModuleType().getId())) {
@@ -397,6 +414,13 @@
 		else
 			setAttribute(PROPERTY_DEPLOY_DIR, deployDir);
 	}
+	
+	/**
+	 * @see ITomcatServerWorkingCopy#setServeModulesWithoutPublish(boolean)
+	 */
+	public void setServeModulesWithoutPublish(boolean b) {
+		setAttribute(PROPERTY_SERVE_MODULES_WITHOUT_PUBLISH, b);
+	}
 
 	/**
 	 * @see ServerDelegate#modifyModules(IModule[], IModule[], IProgressMonitor)
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 b9607e1..11f8c41 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
@@ -18,6 +18,7 @@
 import java.util.List;
 import java.util.Properties;
 
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.*;
 import org.eclipse.debug.core.*;
 import org.eclipse.debug.core.model.IProcess;
@@ -125,8 +126,17 @@
 	protected String[] getRuntimeVMArguments() {
 		IPath installPath = getServer().getRuntime().getLocation();
 		IPath configPath = getRuntimeBaseDirectory();
+		IPath deployPath;
+		// If serving modules without publishing, use workspace path as the deploy path
+		if (getTomcatServer().isServeModulesWithoutPublish()) {
+			deployPath = ResourcesPlugin.getWorkspace().getRoot().getLocation();
+		}
+		// Else normal publishing for modules
+		else {
+			deployPath = getServerDeployDirectory();
+		}
 		return getTomcatVersionHandler().getRuntimeVMArguments(installPath, configPath,
-				getServerDeployDirectory(), getTomcatServer().isTestEnvironment());
+				deployPath, getTomcatServer().isTestEnvironment());
 	}
 	
 	protected String getRuntimePolicyFile() {
@@ -276,16 +286,20 @@
 	 */
 	private void publishDir(int deltaKind, Properties p, IModule module[], IProgressMonitor monitor) throws CoreException {
 		List status = new ArrayList();
-		if (deltaKind == REMOVED) {
-			try {
-				String publishPath = (String) p.get(module[0].getId());
-				File f = new File(publishPath);
-				if (f.exists()) {
-					IStatus[] stat = PublishUtil.deleteDirectory(f, monitor);
-					PublishOperation2.addArrayToList(status, stat);
+		// Remove if requested or if previously published and are now serving without publishing
+		if (deltaKind == REMOVED || getTomcatServer().isServeModulesWithoutPublish()) {
+			String publishPath = (String) p.get(module[0].getId());
+			if (publishPath != null) {
+				try {
+					File f = new File(publishPath);
+					if (f.exists()) {
+						IStatus[] stat = PublishUtil.deleteDirectory(f, monitor);
+						PublishOperation2.addArrayToList(status, stat);
+					}
+				} catch (Exception e) {
+					throw new CoreException(new Status(IStatus.WARNING, TomcatPlugin.PLUGIN_ID, 0,
+							NLS.bind(Messages.errorPublishCouldNotRemoveModule,module[0].getName()), e));
 				}
-			} catch (Exception e) {
-				throw new CoreException(new Status(IStatus.WARNING, TomcatPlugin.PLUGIN_ID, 0, "Could not remove module", e));
 			}
 		} else {
 			IPath path = getModuleDeployDirectory(module[0]);
@@ -307,7 +321,8 @@
 	 * @throws CoreException
 	 */
 	private void publishJar(int kind, int deltaKind, Properties p, IModule[] module, IProgressMonitor monitor) throws CoreException {
-		if (deltaKind == REMOVED) {
+		// Remove if requested or if previously published and are now serving without publishing
+		if (deltaKind == REMOVED || getTomcatServer().isServeModulesWithoutPublish()) {
 			try {
 				String publishPath = (String) p.get(module[1].getId());
 				new File(publishPath).delete();
@@ -340,9 +355,24 @@
 	}
 
 	protected void publishFinish(IProgressMonitor monitor) throws CoreException {
-		// Publish context configuration for servers that support META-INF/context.xml
-		IStatus status = getTomcatConfiguration().publishContextConfig(
-				getRuntimeBaseDirectory(), getServerDeployDirectory(), monitor);
+		IStatus status;
+		IPath baseDir = getRuntimeBaseDirectory();
+		ITomcatVersionHandler tvh = getTomcatVersionHandler();
+		// Include or remove loader jar depending on state of serving directly 
+		status = tvh.prepareForServingDirectly(baseDir, getTomcatServer());
+		if (status.isOK()) {
+			// If serving modules directly, update server.xml accordingly (includes project context.xmls)
+			if (getTomcatServer().isServeModulesWithoutPublish()) {
+				status = getTomcatConfiguration().updateContextsToServeDirectly(
+						baseDir, tvh.getSharedLoader(baseDir), monitor);
+			}
+			// Else serving normally. Add project context.xmls to server.xml
+			else {
+				// Publish context configuration for servers that support META-INF/context.xml
+				status = getTomcatConfiguration().publishContextConfig(
+						baseDir, getServerDeployDirectory(), monitor);
+			}
+		}
 		if (!status.isOK())
 			throw new CoreException(status);
 	}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatSourcePathComputerDelegate.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatSourcePathComputerDelegate.java
index 572bfc9..b9a67e2 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatSourcePathComputerDelegate.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/TomcatSourcePathComputerDelegate.java
@@ -1,5 +1,5 @@
 /**********************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2005, 2006, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,85 +14,137 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.sourcelookup.ISourceContainer;
 import org.eclipse.debug.core.sourcelookup.ISourcePathComputerDelegate;
-import org.eclipse.debug.core.sourcelookup.containers.FolderSourceContainer;
+import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
 import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.jst.server.tomcat.core.internal.wst.IModuleVisitor;
+import org.eclipse.jst.server.tomcat.core.internal.wst.ModuleTraverser;
+import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
 import org.eclipse.wst.server.core.IModule;
 import org.eclipse.wst.server.core.IServer;
 import org.eclipse.wst.server.core.ServerUtil;
+
 /**
- *
+ * 
  */
-public class TomcatSourcePathComputerDelegate implements ISourcePathComputerDelegate {
-	/* (non-Javadoc)
-	 * @see org.eclipse.debug.core.sourcelookup.ISourcePathComputerDelegate#computeSourceContainers(org.eclipse.debug.core.ILaunchConfiguration, org.eclipse.core.runtime.IProgressMonitor)
+public class TomcatSourcePathComputerDelegate implements
+		ISourcePathComputerDelegate {
+
+	/**
+	 * {@inheritDoc}
 	 */
-	public ISourceContainer[] computeSourceContainers(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
-		List classpaths = new ArrayList();
-		classpaths.addAll(Arrays.asList(JavaRuntime.computeUnresolvedSourceLookupPath(configuration)));
-		List sourcefolderList = new ArrayList();
-		
+	public ISourceContainer[] computeSourceContainers(
+			ILaunchConfiguration configuration, IProgressMonitor monitor)
+			throws CoreException {
 		IServer server = ServerUtil.getServer(configuration);
-		if (server != null) {
-			//IPath basePath = ((TomcatServerBehaviour)server.getAdapter(TomcatServerBehaviour.class)).getRuntimeBaseDirectory();
-			List list = new ArrayList();
-			//List pathList = new ArrayList();
-			IModule[] modules = server.getModules();
-			for (int i = 0; i < modules.length; i++) {
-				IProject project = modules[i].getProject();
-				if (project != null) {
-					IFolder moduleFolder = project.getFolder(modules[i].getName());
-					if (moduleFolder.exists()) {
-						sourcefolderList.add(new FolderSourceContainer(moduleFolder, true));
-					}
-					
-					try {
-						if (project.hasNature(JavaCore.NATURE_ID)) {
-							IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
-							if (!list.contains(javaProject))
-								list.add(javaProject);
-						}
-					} catch (Exception e) {
-						// ignore
-					}
-					
-					//IPath path = basePath.append("work").append("Catalina").append("localhost").append(modules[i].getName());
-					//pathList.add(path);
-				}
+
+		SourcePathComputerVisitor visitor = new SourcePathComputerVisitor(
+				configuration);
+
+		IModule[] modules = server.getModules();
+		for (int i = 0; i < modules.length; i++) {
+			ModuleTraverser.traverse(modules[i], visitor, monitor);
+		}
+
+		return visitor.getSourceContainers();
+	}
+
+	class SourcePathComputerVisitor implements IModuleVisitor {
+
+		final ILaunchConfiguration configuration;
+
+		/**
+		 * List<IRuntimeClasspathEntry> of unresolved IRuntimeClasspathEntries
+		 */
+		List runtimeClasspath = new ArrayList();
+
+		SourcePathComputerVisitor(ILaunchConfiguration configuration) {
+			this.configuration = configuration;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public void visitWebComponent(IVirtualComponent component)
+				throws CoreException {
+			IProject project = component.getProject();
+			if (project.hasNature(JavaCore.NATURE_ID)) {
+				IJavaProject javaProject = JavaCore.create(project);
+				runtimeClasspath.add(JavaRuntime
+						.newDefaultProjectClasspathEntry(javaProject));
 			}
-			int size = list.size();
-			IJavaProject[] projects = new IJavaProject[size];
-			list.toArray(projects);
-			
-			for (int i = 0; i < size; i++)
-				classpaths.addAll(Arrays.asList(JavaRuntime.computeUnresolvedRuntimeClasspath(projects[i])));
-			
-			// for (int i = 0; i < size3; i++)
-			//	entries2[size + size2 + i] = JavaRuntime.newArchiveRuntimeClasspathEntry((IPath) pathList.get(i));
 		}
 
-		IRuntimeClasspathEntry[] entries = new IRuntimeClasspathEntry[classpaths.size()];
-		classpaths.toArray(entries);
-
-		IRuntimeClasspathEntry[] resolved = JavaRuntime.resolveSourceLookupPath(entries, configuration);
-		ISourceContainer[] sourceContainers = JavaRuntime.getSourceContainers(resolved);
-		
-		if (!sourcefolderList.isEmpty()) {
-			ISourceContainer[] combinedSourceContainers = new ISourceContainer[sourceContainers.length + sourcefolderList.size()];
-			sourcefolderList.toArray(combinedSourceContainers);
-			System.arraycopy(sourceContainers, 0, combinedSourceContainers, sourcefolderList.size(), sourceContainers.length);
-			sourceContainers = combinedSourceContainers;
+		/**
+		 * {@inheritDoc}
+		 */
+		public void endVisitWebComponent(IVirtualComponent component)
+				throws CoreException {
+			// do nothing
 		}
 
-		return sourceContainers;
+		/**
+		 * {@inheritDoc}
+		 */
+		public void visitArchiveComponent(IPath runtimePath, IPath workspacePath) {
+			// do nothing
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public void visitDependentComponent(IPath runtimePath,
+				IPath workspacePath) {
+			// do nothing
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public void visitWebResource(IPath runtimePath, IPath workspacePath) {
+			// do nothing
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public void visitEarResource(IPath runtimePath, IPath workspacePath) {
+			// do nothing
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public void endVisitEarComponent(IVirtualComponent component)
+				throws CoreException {
+			// do nothing
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public void visitClasspathEntry(IPath rtFolder, IClasspathEntry entry) {
+			// do nothing
+		}
+
+		ISourceContainer[] getSourceContainers() throws CoreException {
+			runtimeClasspath.addAll(Arrays.asList(JavaRuntime
+					.computeUnresolvedSourceLookupPath(configuration)));
+			IRuntimeClasspathEntry[] entries = (IRuntimeClasspathEntry[]) runtimeClasspath
+					.toArray(new IRuntimeClasspathEntry[runtimeClasspath.size()]);
+			IRuntimeClasspathEntry[] resolved = JavaRuntime
+					.resolveSourceLookupPath(entries, configuration);
+			return JavaRuntime.getSourceContainers(resolved);
+		}
+
 	}
 }
\ No newline at end of file
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 7bff3f2..1d733de 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
@@ -18,6 +18,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -27,6 +28,7 @@
 import java.util.Set;
 
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
@@ -34,11 +36,14 @@
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jst.server.core.PublishUtil;
+import org.eclipse.jst.server.tomcat.core.internal.wst.ModuleTraverser;
 import org.eclipse.jst.server.tomcat.core.internal.xml.Factory;
 import org.eclipse.jst.server.tomcat.core.internal.xml.server40.Context;
 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.osgi.util.NLS;
+import org.eclipse.wst.server.core.IModule;
+import org.eclipse.wst.server.core.ServerUtil;
 import org.xml.sax.SAXException;
 
 /**
@@ -155,7 +160,7 @@
 			list.add("-Dcatalina.base=\"" + installPath.toOSString() + "\"");
 		list.add("-Dcatalina.home=\"" + installPath.toOSString() + "\"");
 		// Include a system property for the configurable deploy location
-		list.add("-Dcatalina.deploy=\"" + deployPath.toOSString() + "\"");
+		list.add("-Dwtp.deploy=\"" + deployPath.toOSString() + "\"");
 		list.add("-Djava.endorsed.dirs=\"" + installPath.append("common").append("endorsed").toOSString() + "\"");
 		
 		String[] s = new String[list.size()];
@@ -598,4 +603,132 @@
 		}
 		return Status.OK_STATUS;
 	}
+	
+	/**
+	 * Copies the custom loader jar required to serve projects without
+	 * publishing to the specified destination directory.
+	 * 
+	 * @param destDir destination directory for the loader jar
+	 * @param serverId ID of the server receiving the jar
+	 * @return result of copy operation
+	 */
+	public static IStatus copyLoaderJar(IPath destDir, String serverId) {
+        String loaderJar = "/" + serverId + ".loader.jar";
+        URL installURL = TomcatPlugin.getInstance().getBundle().getEntry(loaderJar);
+        if (installURL == null) {
+			Trace.trace(Trace.SEVERE, "Loader jar not found for server ID " + serverId);
+			return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorPublishLoaderJarNotFound, serverId), null);
+        }
+        	
+        URL localURL;
+        try {
+            localURL = FileLocator.toFileURL(installURL);
+        } catch (IOException e) {
+			Trace.trace(Trace.SEVERE, "Could not convert " + installURL.toString() + " to file URL: " + e.getMessage());
+			return new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(Messages.errorPublishURLConvert,
+					new String[] {installURL.toString(), e.getLocalizedMessage()}), e);
+        }
+		
+        destDir.toFile().mkdirs();
+        IStatus status = FileUtil.copyFile(localURL, destDir.append(loaderJar).toString());        
+        
+		return status;
+	}
+	
+	/**
+	 * Tries to delete the custom loader jar added to support serving projects directly
+	 * without publishing.  Returns a warning if not successful.
+	 *  
+	 * @param destDir destination directory containing the loader jar
+	 * @param serverId ID of the server from which to delete the jar
+	 * @return result of copy operation
+	 */
+	public static IStatus removeLoaderJar(IPath destDir, String serverId) {
+        String loaderJar = "/" + serverId + ".loader.jar";
+        File loaderFile = destDir.append(loaderJar).toFile();
+        // If loader jar exists but is not successfully deleted, return warning
+        if (loaderFile.exists() && !loaderFile.delete())
+        	return new Status(IStatus.WARNING, TomcatPlugin.PLUGIN_ID, 0,
+        			NLS.bind(Messages.errorPublishCantDeleteLoaderJar, loaderFile.getPath()), null);
+
+        return Status.OK_STATUS;
+	}
+	/**
+	 * Updates the catalina.properties file to include a extra entry in the
+	 * specified loader property to pickup the loader jar.
+	 * 
+	 * @param baseDir directory where the Catalina instance is found
+	 * @param jarLoc location of loader jar relative to baseDir
+	 * @param loader loader in catalina.properties to use
+	 * @return result of update operation
+	 */
+	public static IStatus updatePropertiesToServeDirectly(IPath baseDir, String jarLoc, String loader) {
+            File catalinaProperties = baseDir.append(
+                    "conf/catalina.properties").toFile();
+            try {
+            	CatalinaPropertiesUtil.addGlobalClasspath(catalinaProperties, loader,
+            			new String[] { "${catalina.base}/" + jarLoc + "/*.jar" });
+
+            } catch (IOException e) {
+            	return new Status(IStatus.ERROR,TomcatPlugin.PLUGIN_ID,
+            			NLS.bind(Messages.errorPublishCatalinaProps, e.getLocalizedMessage()), e);
+            }
+            return Status.OK_STATUS;
+	}
+	
+	/**
+	 * Update Contexts to serve web projects directly.
+	 * 
+	 * @param baseDir directory where the Catalina instance is found
+	 * @param loader name of the catalina.properties loader to use for global
+	 * classpath entries
+	 * @param monitor a progress monitor
+	 * @return result of update operation
+	 */
+	public static IStatus updateContextsToServeDirectly(IPath baseDir, String loader, IProgressMonitor monitor) {
+
+		IPath confDir = baseDir.append("conf");
+		IPath serverXml = confDir.append("server.xml");
+		try {
+			monitor = ProgressUtil.getMonitorFor(monitor);
+			monitor.beginTask(Messages.publishConfigurationTask, 300);
+
+			monitor.subTask(Messages.publishContextConfigTask);
+			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);
+
+			boolean modified = false;
+
+			// care about top-level modules only
+			TomcatPublishModuleVisitor visitor = new TomcatPublishModuleVisitor(
+					baseDir, publishedInstance, loader);
+			Context [] contexts = publishedInstance.getContexts();
+			for (int i = 0; i < contexts.length; i++) {
+				String moduleId = contexts[i].getSource();
+				if (moduleId != null && moduleId.length() > 0) {
+					IModule module = ServerUtil.getModule(moduleId);
+					ModuleTraverser.traverse(module, visitor, monitor);
+					modified = true;
+				}
+			}
+
+			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.");
+		} catch (Exception e) {
+			Trace.trace(Trace.SEVERE, "Could not modify context configurations to serve directly for Tomcat configuration " + confDir.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;
+	}
 }
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetServeModulesWithoutPublishCommand.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetServeModulesWithoutPublishCommand.java
new file mode 100644
index 0000000..9eff331
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetServeModulesWithoutPublishCommand.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal.command;
+
+import org.eclipse.jst.server.tomcat.core.internal.ITomcatServerWorkingCopy;
+import org.eclipse.jst.server.tomcat.core.internal.Messages;
+/**
+ * Command to enable or disable serving modules without publishing
+ */
+public class SetServeModulesWithoutPublishCommand extends ServerCommand {
+	protected boolean smwp;
+	protected boolean oldSmwp;
+
+	/**
+	 * SetTestEnvironmentCommand constructor comment.
+	 * 
+	 * @param server a Tomcat server
+	 * @param smwp <code>true</code> to enable serving modules without
+	 * publishing. Otherwise modules are served with standard publishing.
+	 */
+	public SetServeModulesWithoutPublishCommand(ITomcatServerWorkingCopy server, boolean smwp) {
+		super(server, Messages.serverEditorActionSetServeWithoutPublish);
+		this.smwp = smwp;
+	}
+
+	/**
+	 * Execute the command.
+	 */
+	public void execute() {
+		oldSmwp = server.isServeModulesWithoutPublish();
+		server.setServeModulesWithoutPublish(smwp);
+	}
+
+	/**
+	 * Undo the command.
+	 */
+	public void undo() {
+		server.setServeModulesWithoutPublish(oldSmwp);
+	}
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetTestEnvironmentCommand.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetTestEnvironmentCommand.java
index 53eb6c3..394df2d 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetTestEnvironmentCommand.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/command/SetTestEnvironmentCommand.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/wst/IModuleVisitor.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/wst/IModuleVisitor.java
new file mode 100644
index 0000000..b31bc25
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/wst/IModuleVisitor.java
@@ -0,0 +1,78 @@
+/**********************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Igor Fedorenko & Fabrizio Giustina - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal.wst;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
+
+/**
+ * Visitor interface to process module components
+ */
+public interface IModuleVisitor {
+
+	/**
+	 * Process web component
+	 * @param component web component to process
+	 * @throws CoreException
+	 */
+	void visitWebComponent(IVirtualComponent component) throws CoreException;
+
+	/**
+	 * Post process web component
+	 * @param component web componet to process
+	 * @throws CoreException
+	 */
+	void endVisitWebComponent(IVirtualComponent component) throws CoreException;
+
+	/**
+	 * Process archive component.
+	 * @param runtimePath path for component at runtime
+	 * @param workspacePath path to component in workspace
+	 */
+	void visitArchiveComponent(IPath runtimePath, IPath workspacePath);
+
+	/**
+	 * Process dependent component.
+	 * @param runtimePath path for component at runtime
+	 * @param workspacePath path to component in workspace
+	 */
+	void visitDependentComponent(IPath runtimePath, IPath workspacePath);
+
+	/**
+	 * Process web resource.
+	 * @param runtimePath path for resource at runtime
+	 * @param workspacePath path to resource in workspace
+	 */
+	void visitWebResource(IPath runtimePath, IPath workspacePath);
+
+	/**
+	 * Process EAR resource.
+	 * @param runtimePath path for resource at runtime
+	 * @param workspacePath path to resource in workspace
+	 */
+	void visitEarResource(IPath runtimePath, IPath workspacePath);
+
+	/**
+	 * Post process EAR resource.
+	 * @param component EAR componet to process
+	 * @throws CoreException 
+	 */
+	void endVisitEarComponent(IVirtualComponent component) throws CoreException;
+
+	/**
+	 * Process a classpath entry.
+	 * @param rtFolder path for class folder at runtime
+	 * @param entry classpath entry
+	 */
+	void visitClasspathEntry(IPath rtFolder, IClasspathEntry entry);
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/wst/ModuleTraverser.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/wst/ModuleTraverser.java
new file mode 100644
index 0000000..02aa3f2
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/wst/ModuleTraverser.java
@@ -0,0 +1,273 @@
+/**********************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Igor Fedorenko & Fabrizio Giustina - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal.wst;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jst.j2ee.componentcore.util.EARArtifactEdit;
+import org.eclipse.jst.server.tomcat.core.internal.TomcatPlugin;
+import org.eclipse.jst.server.tomcat.core.internal.Trace;
+import org.eclipse.wst.common.componentcore.ComponentCore;
+import org.eclipse.wst.common.componentcore.UnresolveableURIException;
+import org.eclipse.wst.common.componentcore.internal.ComponentResource;
+import org.eclipse.wst.common.componentcore.internal.ReferencedComponent;
+import org.eclipse.wst.common.componentcore.internal.StructureEdit;
+import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent;
+import org.eclipse.wst.common.componentcore.internal.impl.ModuleURIUtil;
+import org.eclipse.wst.common.componentcore.internal.impl.PlatformURLModuleConnection;
+import org.eclipse.wst.common.componentcore.internal.resources.VirtualArchiveComponent;
+import org.eclipse.wst.common.componentcore.internal.util.IModuleConstants;
+import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
+import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
+import org.eclipse.wst.server.core.IModule;
+
+/**
+ * Temporary solution for https://bugs.eclipse.org/bugs/show_bug.cgi?id=103888
+ */
+public class ModuleTraverser {
+
+	/**
+	 * Facet type for EAR modules
+	 */
+    public static final String EAR_MODULE = IModuleConstants.JST_EAR_MODULE;
+
+    /**
+     * Facet type for Web modules
+     */
+    public static final String WEB_MODULE = IModuleConstants.JST_WEB_MODULE;
+
+    /**
+     * Facet type for utility modules
+     */
+    public static final String UTILITY_MODULE = IModuleConstants.JST_UTILITY_MODULE;
+
+    /**
+     * Scans the module using the specified visitor.
+     * 
+     * @param module module to traverse
+     * @param visitor visitor to handle resources
+     * @param monitor a progress monitor
+     * @throws CoreException
+     */
+    public static void traverse(IModule module, IModuleVisitor visitor,
+            IProgressMonitor monitor) throws CoreException {
+        if (module == null || module.getModuleType() == null)
+            return;
+
+        String typeId = module.getModuleType().getId();
+        IVirtualComponent component = ComponentCore.createComponent(module.getProject());
+
+        if (component == null) {
+            // can happen if project has been closed
+            Trace.trace(Trace.WARNING, "Unable to create component for module "
+                    + module.getName());
+            return;
+        }
+
+        if (EAR_MODULE.equals(typeId)) {
+            traverseEarComponent(component, visitor, monitor);
+        } else if (WEB_MODULE.equals(typeId)) {
+            traverseWebComponent(component, visitor, monitor);
+        }
+    }
+
+    private static void traverseEarComponent(IVirtualComponent component,
+            IModuleVisitor visitor, IProgressMonitor monitor)
+            throws CoreException {
+        EARArtifactEdit earEdit = EARArtifactEdit
+                .getEARArtifactEditForRead(component);
+        if (earEdit != null) {
+            IVirtualReference[] j2eeComponents = earEdit.getJ2EEModuleReferences();
+            for (int i = 0; i < j2eeComponents.length; i++) {
+                traverseWebComponent(
+                        j2eeComponents[i].getReferencedComponent(), visitor,
+                        monitor);
+            }
+            IVirtualReference[] jarComponents = earEdit.getUtilityModuleReferences();
+            for (int i = 0; i < jarComponents.length; i++) {
+                IVirtualReference jarReference = jarComponents[i];
+                IVirtualComponent jarComponent = jarReference
+                        .getReferencedComponent();
+                IProject dependentProject = jarComponent.getProject();
+                if (!dependentProject.hasNature(JavaCore.NATURE_ID))
+                    continue;
+                IJavaProject project = JavaCore.create(dependentProject);
+                IClasspathEntry cpe = getClasspathEntry(project, jarComponent
+                        .getRootFolder().getProjectRelativePath());
+                visitor.visitEarResource(null, getOSPath(dependentProject,
+                        project, cpe.getOutputLocation()));
+            }
+        }
+        visitor.endVisitEarComponent(component);
+    }
+
+    private static void traverseWebComponent(IVirtualComponent component,
+            IModuleVisitor visitor, IProgressMonitor monitor)
+            throws CoreException {
+
+        visitor.visitWebComponent(component);
+
+        IProject proj = component.getProject();
+        StructureEdit warStruct = StructureEdit.getStructureEditForRead(proj);
+        try {
+            WorkbenchComponent comp = warStruct.getComponent();
+            if (comp == null) {
+                Trace.trace(Trace.SEVERE,
+                        "Error getting WorkbenchComponent from war project. IProject=\""
+                                + proj + "\" StructureEdit=\"" + warStruct
+                                + "\" WorkbenchComponent=\"" + comp + "\"");
+                return;
+            }
+            traverseWebComponentLocalEntries(comp, visitor, monitor);
+
+            // traverse referenced components
+            List children = comp.getReferencedComponents();
+            for (Iterator itor = children.iterator(); itor.hasNext();) {
+                ReferencedComponent childRef = (ReferencedComponent) itor.next();
+                IPath rtFolder = childRef.getRuntimePath();
+                URI refHandle = childRef.getHandle();
+
+                if (PlatformURLModuleConnection.CLASSPATH.equals(
+                		refHandle.segment(ModuleURIUtil.ModuleURI.SUB_PROTOCOL_INDX))) {
+                    IJavaProject jproj = JavaCore.create(proj);
+                    String classpathKind = refHandle.segment(1);
+                    IPath classpathRef = getSuffixPath(refHandle, 2);
+
+                    visitor.visitClasspathEntry(rtFolder, getClasspathEntry(
+                            jproj, classpathKind, classpathRef));
+                } else {
+                    try {
+                        WorkbenchComponent childCom = warStruct.findComponentByURI(refHandle);
+                        if (childCom == null) {
+                            continue;
+                        }
+
+                        traverseDependentEntries(visitor, rtFolder, childCom,
+                                monitor);
+                    } catch (UnresolveableURIException e) {
+                        TomcatPlugin.log(e);
+                    }
+                }
+            }
+        } finally {
+            warStruct.dispose();
+        }
+
+        visitor.endVisitWebComponent(component);
+    }
+
+    private static IPath getSuffixPath(URI uri, int index) {
+        StringBuffer result = new StringBuffer();
+        String[] segments = uri.segments();
+        for (int i = index; i < segments.length; i++) {
+            if (i > index)
+                result.append('/');
+            result.append(segments[i]);
+        }
+        return new Path(result.toString());
+    }
+
+    private static void traverseWebComponentLocalEntries(
+            WorkbenchComponent comp, IModuleVisitor visitor,
+            IProgressMonitor monitor) throws CoreException {
+        IProject warProject = StructureEdit.getContainingProject(comp);
+        if (warProject == null || !warProject.hasNature(JavaCore.NATURE_ID)) {
+            return;
+        }
+        IJavaProject project = JavaCore.create(warProject);
+
+        List res = comp.getResources();
+        for (Iterator itorRes = res.iterator(); itorRes.hasNext();) {
+            ComponentResource childComp = (ComponentResource) itorRes.next();
+            IClasspathEntry cpe = getClasspathEntry(project, childComp.getSourcePath());
+            if (cpe == null)
+                continue;
+            visitor.visitWebResource(childComp.getRuntimePath(), getOSPath(
+                    warProject, project, cpe.getOutputLocation()));
+        }
+    }
+
+    private static void traverseDependentEntries(IModuleVisitor visitor,
+            IPath runtimeFolder, WorkbenchComponent component,
+            IProgressMonitor monitor) throws CoreException {
+        IProject dependentProject = StructureEdit.getContainingProject(component);
+        if (!dependentProject.hasNature(JavaCore.NATURE_ID))
+            return;
+        IJavaProject project = JavaCore.create(dependentProject);
+
+        String name = component.getName(); // assume it is the same as URI
+
+        // go thru all entries
+        List res = component.getResources();
+        for (Iterator itorRes = res.iterator(); itorRes.hasNext();) {
+            ComponentResource childComp = (ComponentResource) itorRes.next();
+            IPath rtPath = childComp.getRuntimePath();
+            IClasspathEntry cpe = getClasspathEntry(project, childComp.getSourcePath());
+            if (cpe == null)
+                continue;
+            visitor.visitDependentComponent(runtimeFolder.append(rtPath)
+                    .append(name + ".jar"), getOSPath(dependentProject,
+                    project, cpe.getOutputLocation()));
+        }
+    }
+
+    private static IClasspathEntry getClasspathEntry(IJavaProject project,
+            IPath sourcePath) throws JavaModelException {
+        sourcePath = project.getPath().append(sourcePath);
+        IClasspathEntry[] cp = project.getRawClasspath();
+        for (int i = 0; i < cp.length; i++) {
+            if (sourcePath.equals(cp[i].getPath()))
+                return JavaCore.getResolvedClasspathEntry(cp[i]);
+        }
+        return null;
+    }
+
+    private static IClasspathEntry getClasspathEntry(IJavaProject project,
+            String classpathKind, IPath classpathRef) throws JavaModelException {
+        int entryKind;
+        if (VirtualArchiveComponent.LIBARCHIVETYPE.equals(classpathKind)) {
+            entryKind = IClasspathEntry.CPE_LIBRARY;
+        } else if (VirtualArchiveComponent.VARARCHIVETYPE.equals(classpathKind)) {
+            entryKind = IClasspathEntry.CPE_VARIABLE;
+        } else {
+            return null;
+        }
+        IClasspathEntry[] cp = project.getRawClasspath();
+        for (int i = 0; i < cp.length; i++) {
+            if (entryKind == cp[i].getEntryKind()
+                    && classpathRef.equals(cp[i].getPath())) {
+                return JavaCore.getResolvedClasspathEntry(cp[i]);
+            }
+        }
+        return null;
+    }
+
+    private static IPath getOSPath(IProject project, IJavaProject javaProject,
+            IPath outputPath) throws JavaModelException {
+        if (outputPath == null)
+            outputPath = javaProject.getOutputLocation();
+        return ResourcesPlugin.getWorkspace().getRoot().getFolder(outputPath)
+                .getLocation();
+    }
+
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Context.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Context.java
index b597c89..9197dd8 100644
--- a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Context.java
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Context.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * Copyright (c) 2003, 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,47 +15,112 @@
  * 
  */
 public class Context extends XMLElement {
+	/**
+	 * Default constructor
+	 */
 	public Context() {
 		// do nothing
 	}
 
+	/**
+	 * Get debug attribute.
+	 * @return debug attribute value
+	 */
 	public String getDebug() {
 		return getAttributeValue("debug");
 	}
 
+	/**
+	 * Get docBase attribute.
+	 * @return docBase attribute value
+	 */
 	public String getDocBase() {
 		return getAttributeValue("docBase");
 	}
 
+	/**
+	 * Get path attribute.
+	 * @return path attribute value
+	 */
 	public String getPath() {
 		return getAttributeValue("path");
 	}
 
+	/**
+	 * Get reloadable attribute.
+	 * @return reloadable attribute value
+	 */
 	public String getReloadable() {
 		return getAttributeValue("reloadable");
 	}
 
+	/**
+	 * Get WTP source attribute. Links the context
+	 * to a project module.
+	 * @return source attribute value
+	 */
 	public String getSource() {
 		return getAttributeValue("source");
 	}
 
+	/**
+	 * Get context Resources element.  Will create
+	 * the element if it does not already exist.
+	 * @return resources element.
+	 */
+	public Resources getResources() {
+		return (Resources) findElement("Resources");
+	}
+
+	/**
+	 * Get context Loader element.  Will create
+	 * the element if it does not already exist.
+	 * @return loader element.
+	 */
+	public Loader getLoader() {
+		return (Loader) findElement("Loader");
+	}
+	
+	/**
+	 * Set debug attribute
+	 * @param debug value to set
+	 */
 	public void setDebug(String debug) {
 		setAttributeValue("debug", debug);
 	}
 
+	/**
+	 * Set docBase attribute.
+	 * @param docBase value to set
+	 */
 	public void setDocBase(String docBase) {
 		setAttributeValue("docBase", docBase);
 	}
 
+	/**
+	 * Set path attribute.
+	 * @param path value to set
+	 */
 	public void setPath(String path) {
 		setAttributeValue("path", path);
 	}
 
+	/**
+	 * Set reloadable attribute.
+	 * @param reloadable value to set
+	 */
 	public void setReloadable(String reloadable) {
 		setAttributeValue("reloadable", reloadable);
 	}
 
+	/**
+	 * Set WTP source attribute. Links the context
+	 * to a project module.
+	 * @param source value to set
+	 */
 	public void setSource(String source) {
 		setAttributeValue("source", source);
 	}
+	
+	
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Loader.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Loader.java
new file mode 100644
index 0000000..55b7ccb
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Loader.java
@@ -0,0 +1,70 @@
+/**********************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Fabrizio Giustina - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal.xml.server40;
+
+import org.eclipse.jst.server.tomcat.core.internal.xml.XMLElement;
+
+/**
+ * Loader element, optional in Context.
+ */
+public class Loader extends XMLElement {
+
+	/**
+	 * Get className attribute.
+     * @return className attribute value
+     */
+    public String getClassName() {
+        return getAttributeValue("className");
+    }
+
+    /**
+     * Set className attribute.
+     * @param className value to set
+     */
+    public void setClassName(String className) {
+        setAttributeValue("className", className);
+    }
+
+    /**
+     * Get WTP virtualClasspath attribute.
+     * @return virtualClasspath value
+     */
+    public String getVirtualClasspath() {
+        return getAttributeValue("virtualClasspath");
+    }
+
+    /**
+     * Set WTP virtualClasspath attribute.
+     * @param virtualClasspath value to set
+     */
+    public void setVirtualClasspath(String virtualClasspath) {
+        setAttributeValue("virtualClasspath", virtualClasspath);
+    }
+
+    /**
+     * Get useSystemClassLoaderAsParent attribute
+     * @return useSystemClassLoaderAsParent value
+     */
+    public String getUseSystemClassLoaderAsParent() {
+        return getAttributeValue("useSystemClassLoaderAsParent");
+    }
+
+    /**
+     * Set useSystemClassLoaderAsParent attribute.
+     * @param useSystemClassLoaderAsParent value to set
+     */
+    public void setUseSystemClassLoaderAsParent(
+            String useSystemClassLoaderAsParent) {
+        setAttributeValue("useSystemClassLoaderAsParent",
+                useSystemClassLoaderAsParent);
+    }
+
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Resources.java b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Resources.java
new file mode 100644
index 0000000..6163e62
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat/core/internal/xml/server40/Resources.java
@@ -0,0 +1,51 @@
+/**********************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *    Fabrizio Giustina - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.jst.server.tomcat.core.internal.xml.server40;
+
+import org.eclipse.jst.server.tomcat.core.internal.xml.XMLElement;
+
+/**
+ * Resources element, optional in Context.
+ */
+public class Resources extends XMLElement {
+
+	/**
+	 * Get className attribute
+	 * @return className attribute value
+	 */
+	public String getClassName() {
+		return getAttributeValue("className");
+	}
+
+	/**
+	 * Get virtualClasspath attribute.
+	 * @return virtualClasspath attribute value
+	 */
+	public String getVirtualClasspath() {
+		return getAttributeValue("virtualClasspath");
+	}
+
+	/**
+	 * Set className attribute.
+	 * @param className value to set
+	 */
+	public void setClassName(String className) {
+		setAttributeValue("className", className);
+	}
+
+	/**
+	 * Set virtualClasspath attribute.
+	 * @param virtualClasspath value to set
+	 */
+	public void setVirtualClasspath(String virtualClasspath) {
+		setAttributeValue("virtualClasspath", virtualClasspath);
+	}
+}
diff --git a/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.java b/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.java
index 0dceefc..72805ce 100644
--- a/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.java
+++ b/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.java
@@ -66,8 +66,11 @@
 	public static String serverEditorServerDir;
 	public static String serverEditorDeployDir;
 	public static String serverEditorTestEnvironment;
+	public static String serverEditorNoPublish;
 	public static String serverEditorSecure;
 	public static String serverEditorDebugMode;
+	public static String serverEditorNotSupported;
+	public static String errorNoPublishServerMustBeStopped;
 	public static String errorServerDirIsRoot;
 	public static String errorServerDirUnderRoot;
 	public static String errorDeployDirNotSpecified;
diff --git a/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.properties b/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.properties
index e6225a4..69d3219 100644
--- a/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.properties
+++ b/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/Messages.properties
@@ -91,9 +91,12 @@
 serverEditorSecure=Enable security
 serverEditorDebugMode=Enable Tomcat debug mode (v4.x and above only)
 serverEditorTestEnvironment=Run modules directly from the workspace (do not modify the Tomcat installation)
+serverEditorNoPublish=Serve modules without publishing {0}
 errorServerDirIsRoot=The server path may not be set to the the root of your workspace.
 errorServerDirUnderRoot=The server path may not be under the \"{0}\" folder of your workspace unless it is the internally supplied path.
 errorDeployDirNotSpecified=A deploy path must be specified.
+serverEditorNotSupported= (not supported by this Tomcat version)
+errorNoPublishServerMustBeStopped=The server must be stopped before a change to the \"{0}\" setting can be saved.
 
 # Browse for Server dialog
 serverEditorBrowseServerMessage=Select a server directory.
diff --git a/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/editor/ServerGeneralEditorSection.java b/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/editor/ServerGeneralEditorSection.java
index a063d0d..cc62e0f 100644
--- a/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/editor/ServerGeneralEditorSection.java
+++ b/plugins/org.eclipse.jst.server.tomcat.ui/tomcatui/org/eclipse/jst/server/tomcat/ui/internal/editor/ServerGeneralEditorSection.java
@@ -13,11 +13,17 @@
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jst.server.tomcat.core.internal.ITomcatServer;
 import org.eclipse.jst.server.tomcat.core.internal.TomcatServer;
 import org.eclipse.jst.server.tomcat.core.internal.command.SetDebugModeCommand;
 import org.eclipse.jst.server.tomcat.core.internal.command.SetSecureCommand;
+import org.eclipse.jst.server.tomcat.core.internal.command.SetServeModulesWithoutPublishCommand;
 import org.eclipse.jst.server.tomcat.ui.internal.ContextIds;
 import org.eclipse.jst.server.tomcat.ui.internal.Messages;
+import org.eclipse.jst.server.tomcat.ui.internal.TomcatUIPlugin;
+import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
@@ -32,8 +38,9 @@
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Section;
 import org.eclipse.ui.help.IWorkbenchHelpSystem;
-
-import org.eclipse.wst.server.ui.editor.*;
+import org.eclipse.wst.server.core.IServer;
+import org.eclipse.wst.server.core.internal.PublishServerJob;
+import org.eclipse.wst.server.ui.editor.ServerEditorSection;
 /**
  * Tomcat server general editor page.
  */
@@ -42,9 +49,12 @@
 
 	protected Button secure;
 	protected Button debug;
+	protected Button noPublish;
 	protected boolean updating;
 
 	protected PropertyChangeListener listener;
+	
+	protected boolean noPublishChanged;
 
 	/**
 	 * ServerGeneralEditorPart constructor comment.
@@ -68,6 +78,11 @@
 				} else if (TomcatServer.PROPERTY_DEBUG.equals(event.getPropertyName())) {
 					Boolean b = (Boolean) event.getNewValue();
 					ServerGeneralEditorSection.this.debug.setSelection(b.booleanValue());
+				} else if (ITomcatServer.PROPERTY_SERVE_MODULES_WITHOUT_PUBLISH.equals(event.getPropertyName())) {
+					Boolean b = (Boolean) event.getNewValue();
+					ServerGeneralEditorSection.this.noPublish.setSelection(b.booleanValue());
+					// Indicate this setting has changed
+					noPublishChanged = true;
 				}
 				updating = false;
 			}
@@ -104,9 +119,28 @@
 		toolkit.paintBordersFor(composite);
 		section.setClient(composite);
 		
+		// serve modules without publish
+		noPublish = toolkit.createButton(composite, NLS.bind(Messages.serverEditorNoPublish, ""), SWT.CHECK);
+		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		data.horizontalSpan = 3;
+		noPublish.setLayoutData(data);
+		noPublish.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent se) {
+				if (updating)
+					return;
+				updating = true;
+				execute(new SetServeModulesWithoutPublishCommand(tomcatServer, noPublish.getSelection()));
+				// Indicate this setting has changed
+				noPublishChanged = true;
+				updating = false;
+			}
+		});
+		// TODO Address help
+//		whs.setHelp(noPublish, ContextIds.SERVER_EDITOR_SECURE);
+
 		// security
 		secure = toolkit.createButton(composite, Messages.serverEditorSecure, SWT.CHECK);
-		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
 		data.horizontalSpan = 3;
 		secure.setLayoutData(data);
 		secure.addSelectionListener(new SelectionAdapter() {
@@ -167,6 +201,16 @@
 		if (secure == null || tomcatServer == null)
 			return;
 		updating = true;
+		
+		boolean supported = tomcatServer.getTomcatVersionHandler().supportsServeModulesWithoutPublish();
+		String noPublishLabel = NLS.bind(Messages.serverEditorNoPublish,
+				supported ? "" : Messages.serverEditorNotSupported);
+		noPublish.setText(noPublishLabel);
+		noPublish.setSelection(tomcatServer.isServeModulesWithoutPublish());
+		if (readOnly || !supported)
+			noPublish.setEnabled(false);
+		else
+			noPublish.setEnabled(true);
 
 		secure.setSelection(tomcatServer.isSecure());
 		if (server.getRuntime() != null && server.getRuntime().getRuntimeType().getId().indexOf("32") >= 0 || readOnly)
@@ -183,4 +227,27 @@
 		
 		updating = false;
 	}
+
+	/**
+	 * @see ServerEditorSection#getSaveStatus()
+	 */
+	public IStatus[] getSaveStatus() {
+		// If serve modules without publishing has changed, request clean publish to be safe
+		if (noPublishChanged) {
+			// If server is running, abort the save since clean publish won't succeed
+			if (tomcatServer.getServer().getServerState() != IServer.STATE_STOPPED) {
+				return new IStatus [] {
+						new Status(IStatus.ERROR, TomcatUIPlugin.PLUGIN_ID,
+								NLS.bind(Messages.errorNoPublishServerMustBeStopped,
+										NLS.bind(Messages.serverEditorNoPublish, "").trim()))
+				};
+			}
+			// Force a clean publish
+			PublishServerJob publishJob = new PublishServerJob(tomcatServer.getServer(), IServer.PUBLISH_CLEAN, false);
+			publishJob.schedule();
+			noPublishChanged = false;
+		}
+		// use default implementation to return success
+		return super.getSaveStatus();
+	}
 }
\ No newline at end of file