[124189] Cache module resources during publish
diff --git a/plugins/org.eclipse.jst.server.core/sjavacore/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java b/plugins/org.eclipse.jst.server.core/sjavacore/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java
index d073d2d..4dccdf6 100644
--- a/plugins/org.eclipse.jst.server.core/sjavacore/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java
+++ b/plugins/org.eclipse.jst.server.core/sjavacore/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java
@@ -151,6 +151,8 @@
 	 * @return a possibly empty array of classpath entries
 	 */
 	public IClasspathEntry[] resolveClasspathContainerImpl(IRuntime runtime) {
+		if (runtime == null)
+			return new IClasspathEntry[0];
 		runtimePathMap.put(runtime.getId(), runtime.getLocation());
 		IClasspathEntry[] entries = resolveClasspathContainer(runtime);
 		
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 16f1aed..be18324 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
@@ -21,8 +21,9 @@
 import org.eclipse.wst.server.core.model.IModuleResourceDelta;
 import org.eclipse.wst.server.core.model.PublishOperation;
 import org.eclipse.wst.server.core.model.ServerBehaviourDelegate;
-import org.eclipse.wst.server.core.util.ProjectModule;
-
+/**
+ * Tomcat publish helper.
+ */
 public class PublishOperation2 extends PublishOperation {
 	protected TomcatServerBehaviour server;
 	protected IModule[] module;
@@ -66,8 +67,7 @@
 		}
 		
 		if (kind == IServer.PUBLISH_CLEAN || kind == IServer.PUBLISH_FULL) {
-			ProjectModule pm = (ProjectModule) module2.loadAdapter(ProjectModule.class, monitor);
-			IModuleResource[] mr = pm.members();
+			IModuleResource[] mr = server.getResources(module);
 			PublishUtil.copy(mr, path);
 			return;
 		}
@@ -104,8 +104,7 @@
 		if (!path.toFile().exists())
 			path.toFile().mkdirs();
 		
-		ProjectModule pm = (ProjectModule) module[1].loadAdapter(ProjectModule.class, monitor);
-		IModuleResource[] mr = pm.members();
+		IModuleResource[] mr = server.getResources(module);
 		PublishUtil.createZipFile(mr, jarPath);
 	}
 }
\ No newline at end of file
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 5ba1a99..5b4b725 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
@@ -252,7 +252,7 @@
 		}
 		
 		if (moduleTree.length == 1) // web module
-			publishDir(deltaKind, p, moduleTree[0], monitor);
+			publishDir(deltaKind, p, moduleTree, monitor);
 		else // utility jar
 			publishJar(kind, deltaKind, p, moduleTree, monitor);
 		
@@ -274,21 +274,19 @@
 	 * @param monitor
 	 * @throws CoreException
 	 */
-	private void publishDir(int deltaKind, Properties p, IModule module, IProgressMonitor monitor) throws CoreException {
+	private void publishDir(int deltaKind, Properties p, IModule module[], IProgressMonitor monitor) throws CoreException {
 		if (deltaKind == REMOVED) {
 			try {
-				String publishPath = (String) p.get(module.getId());
+				String publishPath = (String) p.get(module[0].getId());
 				PublishUtil.deleteDirectory(new File(publishPath), monitor);
 			} catch (Exception e) {
 				throw new CoreException(new Status(IStatus.WARNING, TomcatPlugin.PLUGIN_ID, 0, "Could not remove module", e));
 			}
 		} else {
-			IPath to = getServer().getRuntime().getLocation().append("webapps").append(module.getName());
-			
-			ProjectModule pm = (ProjectModule) module.loadAdapter(ProjectModule.class, monitor);
-			IModuleResource[] mr = pm.members();
+			IPath to = getServer().getRuntime().getLocation().append("webapps").append(module[0].getName());
+			IModuleResource[] mr = getResources(module);
 			PublishUtil.smartCopy(mr, to, monitor);
-			p.put(module.getId(), to.toOSString());
+			p.put(module[0].getId(), to.toOSString());
 		}
 	}
 
@@ -322,8 +320,7 @@
 			if (!path.toFile().exists())
 				path.toFile().mkdirs();
 			
-			ProjectModule pm = (ProjectModule) module[1].loadAdapter(ProjectModule.class, monitor);
-			IModuleResource[] mr = pm.members();
+			IModuleResource[] mr = getResources(module);
 			PublishUtil.createZipFile(mr, path.append(module[1].getName() + ".jar"));
 			p.put(module[1].getId(), path.toOSString());
 		}
@@ -735,6 +732,10 @@
 		workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
 	}
 
+	protected IModuleResource[] getResources(IModule[] module) {
+		return super.getResources(module);
+	}
+
 	protected IModuleResourceDelta[] getPublishedResourceDelta(IModule[] module) {
 		return super.getPublishedResourceDelta(module);
 	}
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModulePublishInfo.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModulePublishInfo.java
index befc4e1..f103f98 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModulePublishInfo.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ModulePublishInfo.java
@@ -12,10 +12,13 @@
 
 import java.util.*;
 import org.eclipse.core.runtime.*;
+import org.eclipse.wst.server.core.IModule;
 import org.eclipse.wst.server.core.IModuleType;
 import org.eclipse.wst.server.core.model.IModuleFile;
 import org.eclipse.wst.server.core.model.IModuleFolder;
 import org.eclipse.wst.server.core.model.IModuleResource;
+import org.eclipse.wst.server.core.model.IModuleResourceDelta;
+import org.eclipse.wst.server.core.model.ModuleDelegate;
 /**
  * Publish information for a specific module on a specific server.
  */
@@ -34,6 +37,11 @@
 	private IModuleResource[] resources = new IModuleResource[0];
 	private IModuleType moduleType;
 
+	private boolean useCache;
+	private IModuleResource[] currentResources = null;
+	private IModuleResourceDelta[] delta = null;
+	private boolean hasDelta;
+
 	/**
 	 * ModulePublishInfo constructor.
 	 * 
@@ -179,6 +187,126 @@
 		}
 	}
 
+	/**
+	 * Start using the module cache.
+	 */
+	protected void startCaching() {
+		useCache = true;
+		currentResources = null;
+	}
+
+	/**
+	 * Fill the module cache.
+	 * 
+	 * @param module
+	 */
+	private void fillCache(IModule[] module) {
+		if (currentResources != null)
+			return;
+		try {
+			int size = module.length;
+			ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
+			currentResources = pm.members();
+			
+			delta = ServerPublishInfo.getDelta(resources, currentResources);
+			hasDelta = (delta != null && delta.length > 0);
+		} catch (CoreException ce) {
+			Trace.trace(Trace.WARNING, "Couldn't fill publish cache for " + module);
+		}
+	}
+
+	protected void clearCache() {
+		useCache = false;
+		currentResources = null;
+		delta = null;
+	}
+
+	protected IModuleResource[] getModuleResources(IModule[] module) {
+		if (module == null)
+			return new IModuleResource[0];
+		
+		if (useCache) {
+			fillCache(module);
+			return currentResources;
+		}
+		
+		int size = module.length;
+		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
+		try {
+			if (pm != null)
+				return pm.members();
+		} catch (CoreException ce) {
+			// ignore
+		}
+		return new IModuleResource[0];
+	}
+
+	protected IModuleResourceDelta[] getDelta(IModule[] module) {
+		if (module == null)
+			return new IModuleResourceDelta[0];
+		
+		if (useCache) {
+			fillCache(module);
+			return delta;
+		}
+		
+		int size = module.length;
+		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
+		IModuleResource[] resources2 = null;
+		try {
+			if (pm != null)
+				resources2 = pm.members();
+		} catch (CoreException ce) {
+			// ignore
+		}
+		if (resources2 == null)
+			resources2 = new IModuleResource[0];
+		return ServerPublishInfo.getDelta(getResources(), resources2);
+	}
+
+	protected boolean hasDelta(IModule[] module) {
+		if (module == null)
+			return false;
+		
+		if (useCache) {
+			fillCache(module);
+			return hasDelta;
+		}
+		
+		int size = module.length;
+		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
+		IModuleResource[] resources2 = null;
+		try {
+			if (pm != null)
+				resources2 = pm.members();
+		} catch (CoreException ce) {
+			// ignore
+		}
+		if (resources2 == null)
+			resources2 = new IModuleResource[0];
+		return ServerPublishInfo.hasDelta(getResources(), resources2);
+	}
+
+	public void fill(IModule[] module) {
+		if (module == null)
+			return;
+		
+		if (useCache) {
+			fillCache(module);
+			setResources(currentResources);
+			return;
+		}
+		
+		int size = module.length;
+		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
+		try {
+			if (pm != null)
+				setResources(pm.members());
+		} catch (CoreException ce) {
+			// ignore
+		}
+	}
+
 	public String toString() {
 		return "ModulePublishInfo [" + moduleId + "]";
 	}
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java
index 499537e..2891c27 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/Server.java
@@ -797,6 +797,7 @@
 		stopAutoPublish();
 		
 		try {
+			getServerPublishInfo().startCaching();
 			IStatus status = getBehaviourDelegate(monitor).publish(kind, monitor);
 			
 			final List modules2 = new ArrayList();
@@ -811,6 +812,7 @@
 			}, monitor);
 			
 			getServerPublishInfo().removeDeletedModulePublishInfo(modules2);
+			getServerPublishInfo().clearCache();
 			getServerPublishInfo().save();
 			
 			return status;
@@ -932,7 +934,18 @@
 	/*
 	 * Returns the module resources that have been published.
 	 * 
-	 * @see ServerBehaviourDelegate.getPublishedResources(IModule[], IModule)
+	 * @see ServerBehaviourDelegate.getPublishedResources(IModule[])
+	 */
+	public IModuleResource[] getResources(IModule[] module) {
+		if (module == null)
+			throw new IllegalArgumentException("Module cannot be null");
+		return getServerPublishInfo().getResources(module);
+	}
+
+	/*
+	 * Returns the module resources that have been published.
+	 * 
+	 * @see ServerBehaviourDelegate.getPublishedResources(IModule[])
 	 */
 	public IModuleResource[] getPublishedResources(IModule[] module) {
 		if (module == null)
@@ -944,7 +957,7 @@
 	 * Returns the delta of the current module resources that have been
 	 * published compared to the current state of the module.
 	 * 
-	 * @see ServerBehaviourDelegate.getPublishedResourceDelta(IModule[], IModule)
+	 * @see ServerBehaviourDelegate.getPublishedResourceDelta(IModule[])
 	 */
 	public IModuleResourceDelta[] getPublishedResourceDelta(IModule[] module) {
 		if (module == null)
@@ -956,7 +969,7 @@
 	 * Returns the delta of the current module resources that have been
 	 * published compared to the current state of the module.
 	 * 
-	 * @see ServerBehaviourDelegate.getPublishedResourceDelta(IModule[], IModule)
+	 * @see ServerBehaviourDelegate.getPublishedResourceDelta(IModule[])
 	 */
 	public boolean hasPublishedResourceDelta(IModule[] module) {
 		if (module == null)
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPublishInfo.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPublishInfo.java
index a4eea7c..593501a 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPublishInfo.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPublishInfo.java
@@ -242,36 +242,24 @@
 	 */
 	public void fill(IModule[] module) {
 		ModulePublishInfo mpi = getModulePublishInfo(module);
-		int size = module.length;
-		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
-		try {
-			if (pm != null)
-				mpi.setResources(pm.members());
-		} catch (CoreException ce) {
-			// ignore
-		}
+		mpi.fill(module);
 	}
 
 	protected IModuleResourceDelta[] getDelta(IModule[] module) {
 		if (module == null)
 			return new IModuleResourceDelta[0];
 		
-		ModulePublishInfo mpi = getModulePublishInfo(module);
-		int size = module.length;
-		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
-		IModuleResource[] resources = null;
-		try {
-			if (pm != null)
-				resources = pm.members();
-		} catch (CoreException ce) {
-			// ignore
-		}
-		if (resources == null)
-			resources = new IModuleResource[0];
-		return getDelta(mpi.getResources(), resources);
+		return getModulePublishInfo(module).getDelta(module);
 	}
 
-	protected IModuleResourceDelta[] getDelta(IModuleResource[] original, IModuleResource[] current) {
+	protected IModuleResource[] getResources(IModule[] module) {
+		if (module == null)
+			return new IModuleResource[0];
+		
+		return getModulePublishInfo(module).getModuleResources(module);
+	}
+
+	protected static IModuleResourceDelta[] getDelta(IModuleResource[] original, IModuleResource[] current) {
 		if (original == null || current == null)
 			return new IModuleResourceDelta[0];
 	
@@ -334,22 +322,10 @@
 		if (module == null)
 			return false;
 		
-		ModulePublishInfo mpi = getModulePublishInfo(module);
-		int size = module.length;
-		ModuleDelegate pm = (ModuleDelegate) module[size - 1].loadAdapter(ModuleDelegate.class, null);
-		IModuleResource[] resources = null;
-		try {
-			if (pm != null)
-				resources = pm.members();
-		} catch (CoreException ce) {
-			// ignore
-		}
-		if (resources == null)
-			resources = new IModuleResource[0];
-		return hasDelta(mpi.getResources(), resources);
+		return getModulePublishInfo(module).hasDelta(module);
 	}
 
-	protected boolean hasDelta(IModuleResource[] original, IModuleResource[] current) {
+	protected static boolean hasDelta(IModuleResource[] original, IModuleResource[] current) {
 		if (original == null || current == null)
 			return false;
 		
@@ -388,7 +364,7 @@
 	/**
 	 * Create a resource delta for an entire tree.
 	 */
-	protected IModuleResourceDelta[] getDeltaTree(IModuleResource[] resources, int kind) {
+	private static IModuleResourceDelta[] getDeltaTree(IModuleResource[] resources, int kind) {
 		if (resources == null)
 			return new IModuleResourceDelta[0];
 	
@@ -423,4 +399,26 @@
 	protected boolean hasStructureChanged(List modules) {
 		return modules.size() != modulePublishInfo.keySet().size();
 	}
+
+	/**
+	 * Fill the module cache.
+	 */
+	protected void startCaching() {
+		Iterator iterator = modulePublishInfo.values().iterator();
+		while (iterator.hasNext()) {
+			ModulePublishInfo mpi = (ModulePublishInfo) iterator.next();
+			mpi.startCaching();
+		}
+	}
+
+	/**
+	 * Clears all caches of current module resources and deltas.
+	 */
+	public void clearCache() {
+		Iterator iterator = modulePublishInfo.values().iterator();
+		while (iterator.hasNext()) {
+			ModulePublishInfo mpi = (ModulePublishInfo) iterator.next();
+			mpi.clearCache();
+		}
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/model/ServerBehaviourDelegate.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/model/ServerBehaviourDelegate.java
index 466b374..af7ba25 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/model/ServerBehaviourDelegate.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/model/ServerBehaviourDelegate.java
@@ -451,6 +451,16 @@
 	public abstract void stop(boolean force);
 
 	/**
+	 * Returns the current module resources.
+	 * 
+	 * @param module the module
+	 * @return an array containing the module's resources
+	 */
+	protected IModuleResource[] getResources(IModule[] module) {
+		return server.getResources(module);
+	}
+
+	/**
 	 * Returns the module resources that have been published to the server.
 	 * 
 	 * <p>