[294664] Classpath entry attributes lost when updating runtime classpath container
[295494]	RuntimeClasspathContainer should update runtime if it is null
[291960] XMLViewer makes (apparently) invalid assumptions about TransformerFactory
[282922] Server will not change to republish status after web module changed
[286960]	Cannot delete a module using the delete key button on servers view.
[291261] Invalid matching rule shows in .log
diff --git a/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java b/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java
index b1f40b0..f4f9509 100644
--- a/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java
+++ b/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/RuntimeClasspathProviderDelegate.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2008 IBM Corporation and others.
+ * Copyright (c) 2003, 2009 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
@@ -11,17 +11,12 @@
 package org.eclipse.jst.server.core;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.core.IAccessRule;
 import org.eclipse.jdt.core.IClasspathAttribute;
 import org.eclipse.jdt.core.IClasspathContainer;
 import org.eclipse.jdt.core.IClasspathEntry;
@@ -151,7 +146,8 @@
 			for (int j = 0; j < size2; j++) {
 				SourceAttachmentUpdate sau = sourceAttachments.get(j);
 				if (sau.runtimeId.equals(runtime.getId()) && sau.entry.equals(entries[i].getPath())) {
-					entries[i] = JavaCore.newLibraryEntry(entries[i].getPath(), sau.sourceAttachmentPath, sau.sourceAttachmentRootPath, new IAccessRule[0], sau.attributes, false);
+					IClasspathAttribute[] consolidatedClasspathAttributes = consolidateClasspathAttributes(sau.attributes, entries[i].getExtraAttributes());
+					entries[i] = JavaCore.newLibraryEntry(entries[i].getPath(), sau.sourceAttachmentPath, sau.sourceAttachmentRootPath, entries[i].getAccessRules(), consolidatedClasspathAttributes, false);
 				}
 			}
 		}
@@ -353,4 +349,23 @@
 			Trace.trace(Trace.SEVERE, "Error saving source path info", e);
 		}
 	}
+	
+	public IClasspathAttribute[] consolidateClasspathAttributes(IClasspathAttribute[] sourceAttachmentAttributes, IClasspathAttribute[] classpathEntryAttributes) {
+		List classpathAttributeList = new ArrayList();
+		classpathAttributeList.addAll(Arrays.asList(sourceAttachmentAttributes));
+		for (int i = 0; i < classpathEntryAttributes.length; i++) {
+			boolean attributeCollision = false;
+			for (int j = 0; j < sourceAttachmentAttributes.length; j++) {
+				String name = classpathEntryAttributes[i].getName();
+				if(name != null && name.equals(sourceAttachmentAttributes[j].getName())) {
+					attributeCollision = true;
+					break;
+				}
+			}
+			if(!attributeCollision) {
+				classpathAttributeList.add(classpathEntryAttributes[i]);
+			}
+		}
+		return (IClasspathAttribute[]) classpathAttributeList.toArray(new IClasspathAttribute[classpathAttributeList.size()]);
+	}
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/internal/RuntimeClasspathContainer.java b/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/internal/RuntimeClasspathContainer.java
index d044b05..e76f687 100644
--- a/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/internal/RuntimeClasspathContainer.java
+++ b/plugins/org.eclipse.jst.server.core/src/org/eclipse/jst/server/core/internal/RuntimeClasspathContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2007 IBM Corporation and others.
+ * Copyright (c) 2003, 2009 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
@@ -18,6 +18,7 @@
 
 import org.eclipse.wst.server.core.IRuntime;
 import org.eclipse.wst.server.core.IRuntimeType;
+import org.eclipse.wst.server.core.ServerCore;
 /**
  * 
  */
@@ -69,8 +70,11 @@
 	 */
 	public IClasspathEntry[] getClasspathEntries() {
 		IClasspathEntry[] entries = null;
-		if (delegate != null && runtime != null)
-			entries = delegate.resolveClasspathContainerImpl(project, runtime);
+		
+		IRuntime curRuntime = getRuntime();
+		
+		if (delegate != null && curRuntime != null)
+			entries = delegate.resolveClasspathContainerImpl(project, curRuntime);
 		
 		if (entries == null)
 			return new IClasspathEntry[0];
@@ -78,14 +82,24 @@
 		return entries;
 	}
 
+	private IRuntime getRuntime(){
+		if (runtime == null && runtimeId != null) {
+			// Make sure the runtime object is initialized.
+			runtime = ServerCore.findRuntime(runtimeId);
+		}
+		return runtime;
+	}
+	
 	/** (non-Javadoc)
 	 * @see org.eclipse.jdt.core.IClasspathContainer#getDescription()
 	 */
 	public String getDescription() {
-		if (runtime != null) {
-			IRuntimeType runtimeType = runtime.getRuntimeType();
+		IRuntime curRuntime = getRuntime();
+
+		if (curRuntime != null) {
+			IRuntimeType runtimeType = curRuntime.getRuntimeType();
 			if (runtimeType != null)
-				return NLS.bind(Messages.classpathContainer, runtimeType.getName(), runtime.getName());
+				return NLS.bind(Messages.classpathContainer, runtimeType.getName(), curRuntime.getName());
 		}
 		return NLS.bind(Messages.classpathContainerUnbound, Messages.classpathContainerDescription, runtimeId);
 	}
diff --git a/plugins/org.eclipse.wst.internet.monitor.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.wst.internet.monitor.ui/META-INF/MANIFEST.MF
index 938be77..9b4cc49 100644
--- a/plugins/org.eclipse.wst.internet.monitor.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.wst.internet.monitor.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.wst.internet.monitor.ui; singleton:=true
-Bundle-Version: 1.0.304.qualifier
+Bundle-Version: 1.0.305.qualifier
 Bundle-Activator: org.eclipse.wst.internet.monitor.ui.internal.MonitorUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.wst.internet.monitor.ui/monitorui/org/eclipse/wst/internet/monitor/ui/internal/viewers/XMLViewer.java b/plugins/org.eclipse.wst.internet.monitor.ui/monitorui/org/eclipse/wst/internet/monitor/ui/internal/viewers/XMLViewer.java
index 2029df3..36bce7f 100644
--- a/plugins/org.eclipse.wst.internet.monitor.ui/monitorui/org/eclipse/wst/internet/monitor/ui/internal/viewers/XMLViewer.java
+++ b/plugins/org.eclipse.wst.internet.monitor.ui/monitorui/org/eclipse/wst/internet/monitor/ui/internal/viewers/XMLViewer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2007 IBM Corporation and others.
+ * Copyright (c) 2003, 2009 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
@@ -87,9 +87,16 @@
 				messageLabel.setText(Messages.xmlViewInvalid);
 				return;
 			}
-			if (xmlTagMissing && finalMsg.toLowerCase().startsWith("<?xml version=\"1.0\" encoding=\"utf-8\"?>")) {
-				int x = finalMsg.indexOf("\n") + 1;
+			if (xmlTagMissing && (finalMsg.toLowerCase().startsWith("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
+							|| finalMsg.toLowerCase().startsWith("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>") 
+							|| finalMsg.toLowerCase().startsWith("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>"))) {
+				int x = finalMsg.indexOf(">") + 1;
+				//remove <?xml version="1.0" encoding="UTF-8"?>
 				String Msg = finalMsg.substring(x);
+				//remove starting newlines
+				while (Msg.substring(0, ls).indexOf(lineSeparator) >= 0){
+					Msg = Msg.substring(ls, Msg.length());
+				}
 				finalMsg = Msg;
 				
 				messageText.setText(finalMsg);
@@ -211,6 +218,7 @@
 			Transformer transformer = tf.newTransformer();
 			transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
 			transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
+			transformer.setOutputProperty(OutputKeys.STANDALONE, "no"); //$NON-NLS-1$
 			transformer.transform(source, result);
 		} catch (TransformerConfigurationException e) {
 			throw (IOException) (new IOException().initCause(e));
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 3d3d5f1..d3d8c2d 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
@@ -52,6 +52,12 @@
 	public static final int AUTO_PUBLISH_DISABLE = 1;
 	public static final int AUTO_PUBLISH_ENABLE = 2;
 
+	private static String PUBLISH_AUTO_STRING = "auto";
+	private static String PUBLISH_CLEAN_STRING = "clean";
+	private static String PUBLISH_FULL_STRING = "full";
+	private static String PUBLISH_INCREMENTAL_STRING = "incremental";
+	private static String PUBLISH_UNKOWN = "unkown";
+	
 	protected static final String PROP_HOSTNAME = "hostname";
 	protected static final String SERVER_ID = "server-id";
 	protected static final String RUNTIME_ID = "runtime-id";
@@ -745,6 +751,10 @@
 	protected void handleModuleProjectChange(IModule module) {
 		Trace.trace(Trace.FINEST, "> handleDeployableProjectChange() " + this + " " + module);
 		
+		if (!isModuleDeployed(module)){
+			return;
+		}
+		
 		// check for duplicate jobs already waiting and don't create a new one
 		Job[] jobs = Job.getJobManager().find(ServerUtil.SERVER_JOB_FAMILY);
 		if (jobs != null) {
@@ -765,6 +775,36 @@
 		
 		Trace.trace(Trace.FINEST, "< handleDeployableProjectChange()");
 	}
+	
+	protected boolean isModuleDeployed(final IModule requestedModule){
+		Trace.trace(Trace.FINEST, "> isModuleDeployed()");
+
+		// no modules are deployed
+		if (modules.isEmpty())
+			return false;
+		
+		// shallow search: check for root modules first
+		boolean deployed = modules.contains(requestedModule);
+		
+		if(!deployed){
+			// deep search: look into all the child modules
+			Iterator<IModule> itr = modules.iterator();
+			while(itr.hasNext() && !deployed){
+				IModule[] m = new IModule[] {itr.next()};
+				deployed = !visitModule(m, new IModuleVisitor(){
+					public boolean visit(IModule[] modules2) {
+						for (int i =0;i<=modules2.length-1;i++){
+							if (modules2[i].equals(requestedModule))
+								return false;
+						}
+						return true;
+				}}, null);
+			}
+		}
+		
+		Trace.trace(Trace.FINEST, "< isModuleDeployed() deployed="+deployed);
+		return deployed;
+	}
 
 	protected void stopAutoPublish() {
 		if (autoPublishThread == null)
@@ -2677,6 +2717,7 @@
 
 	protected IStatus publishImpl(int kind, List<IModule[]> modules4, IAdaptable info, IProgressMonitor monitor) {
 		Trace.trace(Trace.FINEST, "-->-- Publishing to server: " + Server.this.toString() + " -->--");
+		Trace.trace(Trace.FINEST, "Server.publishImpl(): kind=<"+getPublishKindString(kind)+"> modules=" + modules4);
 		
 		stopAutoPublish();
 		
@@ -2709,7 +2750,7 @@
 			getServerPublishInfo().save();
 			
 			firePublishFinished(Status.OK_STATUS);
-			Trace.trace(Trace.PERFORMANCE, "Server.publish(): <" + (System.currentTimeMillis() - time) + "> " + getServerType().getId());
+			Trace.trace(Trace.PERFORMANCE, "Server.publishImpl(): <" + (System.currentTimeMillis() - time) + "> " + getServerType().getId());
 			return status;
 		} catch (Exception e) {
 			Trace.trace(Trace.SEVERE, "Error calling delegate publish() " + Server.this.toString(), e);
@@ -3132,4 +3173,20 @@
 	public String toString() {
 		return getName();
 	}
-}
\ No newline at end of file
+	
+	private String getPublishKindString(int kind){
+		if (kind == IServer.PUBLISH_AUTO){
+			return PUBLISH_AUTO_STRING;
+		}
+		else if (kind == IServer.PUBLISH_CLEAN){
+			return PUBLISH_CLEAN_STRING;
+		}
+		else if (kind == IServer.PUBLISH_FULL){
+			return PUBLISH_FULL_STRING;
+		}
+		else if (kind == IServer.PUBLISH_INCREMENTAL){
+			return PUBLISH_INCREMENTAL_STRING;
+		}
+		return PUBLISH_UNKOWN;
+	}
+} 
diff --git a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPlugin.java b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPlugin.java
index c38aae8..157e636 100644
--- a/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPlugin.java
+++ b/plugins/org.eclipse.wst.server.core/servercore/org/eclipse/wst/server/core/internal/ServerPlugin.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2008 IBM Corporation and others.
+ * Copyright (c) 2003, 2009 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
@@ -1157,7 +1157,6 @@
 			|| (b.endsWith(".*") && a.startsWith(b.substring(0, b.length() - 1))))
 			return true;
 		if (a.startsWith(b) || b.startsWith(a)) {
-			ServerPlugin.log(new Status(IStatus.ERROR, ServerPlugin.PLUGIN_ID, "Invalid matching rules used: " + a + "/" + b));
 			Trace.trace(Trace.WARNING, "Invalid matching rules used: " + a + "/" + b);
 			return true;
 		}
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/GlobalDeleteAction.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/GlobalDeleteAction.java
new file mode 100644
index 0000000..4666249
--- /dev/null
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/GlobalDeleteAction.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.wst.server.ui.internal.view.servers;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.actions.SelectionProviderAction;
+import org.eclipse.wst.server.core.IModule;
+import org.eclipse.wst.server.core.IServer;
+import org.eclipse.wst.server.ui.internal.Messages;
+/**
+ * This global delete action handles both the server and module deletion.
+ */
+public class GlobalDeleteAction extends SelectionProviderAction {
+	protected Shell shell;
+	private DeleteAction serverDeleteAction = null;
+	private boolean isRemoveServer = false;
+
+	public GlobalDeleteAction(Shell shell, ISelectionProvider selectionProvider) {
+		super(selectionProvider, Messages.actionDelete);
+		this.shell = shell;
+		setEnabled(false);
+		serverDeleteAction = new DeleteAction(shell, selectionProvider);
+	}
+
+	private boolean isRemoveModuleActionEnabled(IStructuredSelection sel) {
+		if (sel == null || sel.isEmpty())
+			return false;
+			
+		// get selection but avoid no selection or multiple selection
+		IModule[] moduleArray = null;
+		Iterator iterator = sel.iterator();
+		Object obj = iterator.next();
+		if (obj instanceof ModuleServer) {
+			ModuleServer ms = (ModuleServer) obj;
+			moduleArray = ms.module;
+		}
+		 
+		if (iterator.hasNext()) {
+			moduleArray = null;
+		}
+		
+		return (moduleArray == null || moduleArray.length == 1);
+	}
+
+	/**
+	 * Update the enabled state.
+	 * 
+	 * @param sel a selection
+	 */
+	public void selectionChanged(IStructuredSelection sel) {
+		if (sel.isEmpty()) {
+			setEnabled(false);
+			return;
+		}
+
+		// Check if the delete action is enabled or not.
+		serverDeleteAction.selectionChanged(sel);
+		
+		if (serverDeleteAction.isEnabled()) {
+			// The server deletion action is already enabled.
+			isRemoveServer = true;
+			setEnabled(true);
+			return;
+		}
+		
+		// Check the remove module action.
+		if (isRemoveModuleActionEnabled(sel)) {
+			isRemoveServer = false;
+			setEnabled(true);
+		} else {
+			setEnabled(false);
+		}
+	}
+	
+	public void run() {
+		if (isRemoveServer) {
+			// Run the server delete action;
+			serverDeleteAction.run();
+			return;
+		}
+		// get selection but avoid no selection or multiple selection
+		IServer server = null;
+		IModule[] moduleArray = null;
+		IStructuredSelection sel = getStructuredSelection();
+		if (!sel.isEmpty()) {
+			Iterator iterator = sel.iterator();
+			Object obj = iterator.next();
+			
+			// and the method calls serverDeleteAction, then returns
+			if (obj instanceof IServer)
+				server = (IServer) obj;
+			if (obj instanceof ModuleServer) {
+				ModuleServer ms = (ModuleServer) obj;
+				server = ms.server; // even though ms.server is public, let's stick to the getServer call
+				moduleArray = ms.module;
+			}
+
+			if (iterator.hasNext()) {
+				server = null;
+				moduleArray = null;
+			}
+		}
+		
+		if (moduleArray != null && moduleArray.length == 1) {
+			new RemoveModuleAction(shell, server, moduleArray[0]).run();
+		}
+	}
+}
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java
index 5d754ad..21a1fa9 100644
--- a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2008 IBM Corporation and others.
+ * Copyright (c) 2003, 2009 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
@@ -68,7 +68,7 @@
 	// actions on a server
 	protected Action[] actions;
 	protected Action actionModifyModules;
-	protected Action openAction, showInConsoleAction, showInDebugAction, propertiesAction, monitorPropertiesAction;
+	protected Action openAction, showInConsoleAction, showInDebugAction, propertiesAction, monitorPropertiesAction, globalDeleteAction;
 	protected Action copyAction, pasteAction, deleteAction, renameAction;
 
 	/**
@@ -289,10 +289,13 @@
 		pasteAction = new PasteAction(shell, provider, tableViewer.clipboard);
 		copyAction = new CopyAction(provider, tableViewer.clipboard, pasteAction);
 		deleteAction = new DeleteAction(shell, provider);
+		// Create a second delete action that can act in modules, when the delete key is pressed
+		// the old DeleteAction only works for servers see bug# 286960
+		globalDeleteAction = new GlobalDeleteAction(shell, provider);
 		renameAction = new RenameAction(shell, tableViewer, provider);
 		actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
 		actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), pasteAction);
-		actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), deleteAction);
+		actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), globalDeleteAction);
 		actionBars.setGlobalActionHandler(ActionFactory.RENAME.getId(), renameAction);
 		
 		// create the other actions